-
Notifications
You must be signed in to change notification settings - Fork 609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(CL): Add query for Liquidity in Ranges #4691
Conversation
x/concentrated-liquidity/tick.go
Outdated
@@ -183,6 +184,125 @@ func GetMinAndMaxTicksFromExponentAtPriceOne(exponentAtPriceOne sdk.Int) (minTic | |||
return math.GetMinAndMaxTicksFromExponentAtPriceOneInternal(exponentAtPriceOne) | |||
} | |||
|
|||
// GetTickLiquidityForRangeInBatches returns an array of liquidity depth within the given range of lower tick and upper tick. | |||
func (k Keeper) GetTickLiquidityForRange(ctx sdk.Context, poolId uint64, lowerTick, upperTick int64) (sdk.Dec, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We had more discussions with @jonator around this query today and based on the conclusions, I think we can separate 2 queries
- Query for the liquidity depths for the liquidity graph across the entire tick range
- I think we do not need
lowerTick
andupperTick
for that since we need the entire price range for the graph - We return "liquidity depths", that is "total overlapped liquidity for positions within that range" so that frontend already has data in the final format for plotting the graph
- Query for estimating swaps. The chain returns tick liquidity net amounts in the direction of the swap starting from the current current active tick
- The reason we start from the current active tick is that for the context of the swap, we do not need to know the full tick range, only starting from the current one and until the liquidity runs out
- We can specify an upper bound or lower bound here signifying the price impact protection
- Instead of returning liquidity depths here, we simply return
liquidity_net
amounts exactly as they are stored instate.
We can use a very similar algorithm for both queries with minor modifications. I propose to make this PR focus on 1), and I can start integrating #2 by branching off of this PR tomorrow. Let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet, sounds great, revised this PR so that it suits the first query.
x/concentrated-liquidity/tick.go
Outdated
if nextTick.GT(sdk.NewInt(upperTick)) { | ||
break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to my other comment - I don't think we need to use the upperTick
assuming that this query is meant for liquidity graph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed and removed upper tock and lower tick
x/concentrated-liquidity/tick.go
Outdated
currentTick = nextTick.Int64() | ||
|
||
totalLiquidityWithinRange := currentLiquidity | ||
for currentTick <= upperTick { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that instead of looping here and calling swapStrategy.NextInitializedTick
, we can iterate the tick prefix for that pool using this:
osmosis/osmoutils/store_helper.go
Lines 101 to 108 in f447c87
func gatherValuesFromIterator[T any](iterator db.Iterator, parseValue func([]byte) (T, error), stopFn func([]byte) bool) ([]T, error) { | |
// Replace a callback with the one that takes both key and value | |
// but ignores the key. | |
parseKeyValue := func(_ []byte, value []byte) (T, error) { | |
return parseValue(value) | |
} | |
return gatherValuesFromIteratorWithKeyParser(iterator, parseKeyValue, stopFn) | |
} |
I haven't looked deep enough into it so please proceed with caution on this suggestion. However, if we get the iterator to work, it should be considerably more performant than looping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you mind if we create an issue this for further improvements? I have took a look at it, seems like this implementation would take more time than the current implmenetation, while I do not want to block front end for this query time wise.
Some of the implementation I was working on: https://github.com/osmosis-labs/osmosis/compare/mattverse/use-iterator?expand=1
Mainly more time consuming because we need to utilize both key + value used, and we need to parse the key as well to receive the tick index for the key, while we do not have enough helper methods to do this right away
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed and approved, I trust you'll either make an issue or PR a follow up change 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM once new comments are addressed. Nice work!
Nothing blocking and agreed to get v1 in for frontend and work on v2 in the next PR
string lower_tick = 2 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", | ||
(gogoproto.moretags) = "yaml:\"tick\"", | ||
(gogoproto.nullable) = false | ||
]; | ||
string upper_tick = 3 [ | ||
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", | ||
(gogoproto.moretags) = "yaml:\"tick\"", | ||
(gogoproto.nullable) = false | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this should not be removed. This is a proto struct being used to return values for the response
// TickLiquidityInBatches returns array of liquidity depths in the given range of lower tick and upper tick. | ||
// Note that the space between the ticks in the returned array would always be guaranteed spacing greater than given batch unit. | ||
func (q Querier) TotalLiquidityForRange(goCtx context.Context, req *clquery.QueryTotalLiquidityForRangeRequest) (*clquery.QueryTotalLiquidityForRangeResponse, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
godoc needs to be revised
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Godoc revised
x/concentrated-liquidity/tick.go
Outdated
keyTick := types.KeyTick(poolId, nextTick.Int64()) | ||
tickStruct := model.TickInfo{} | ||
found, err := osmoutils.Get(store, keyTick, &tickStruct) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the GetTickByTickIndex
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed :)
x/concentrated-liquidity/tick.go
Outdated
@@ -226,3 +306,17 @@ func (k Keeper) GetPerTickLiquidityDepthFromRange(ctx sdk.Context, poolId uint64 | |||
|
|||
return liquidityDepths, nil | |||
} | |||
|
|||
func (k Keeper) GetTickByTickIndex(ctx sdk.Context, poolId uint64, tickIndex sdk.Int) (model.TickInfo, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: consider unexporting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unexported
|
||
expectedLiquidityDepthForRange []query.LiquidityDepthWithRange | ||
}{ | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a test case with 2 full range and 2 narrow range positions?
I don't think there is one where we have both full range and narrow range
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added :)
Closes: #XXX
What is the purpose of the change
Adds Query for Liquidity in Ranges.
Iterates over all ticks that are initialized starting from min tick, until we hit the upper tick given. We cumulate the liquidity net in the process of iterating it, using the final result in the last iteration as the value for the liquidity.
Brief Changelog
Testing and Verifying
Added new tests.
Documentation and Release Note
Unreleased
section inCHANGELOG.md
? (yes / no)x/<module>/spec/
) / Osmosis docs repo / not documented)