Skip to content
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

Merged
merged 9 commits into from
Mar 23, 2023
Merged

Conversation

mattverse
Copy link
Member

@mattverse mattverse commented Mar 21, 2023

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

  • Add query for Liquidity in Ranges

Testing and Verifying

Added new tests.

Documentation and Release Note

  • Does this pull request introduce a new feature or user-facing behavior changes? (yes / no)
  • Is a relevant changelog entry added to the Unreleased section in CHANGELOG.md? (yes / no)
  • How is the feature or change documented? (not applicable / specification (x/<module>/spec/) / Osmosis docs repo / not documented)

@mattverse mattverse marked this pull request as draft March 21, 2023 13:18
@mattverse mattverse marked this pull request as ready for review March 22, 2023 01:05
@mattverse mattverse added the V:state/breaking State machine breaking PR label Mar 22, 2023
@mattverse mattverse requested a review from p0mvn March 22, 2023 01:17
@@ -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) {
Copy link
Member

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

  1. Query for the liquidity depths for the liquidity graph across the entire tick range
  • I think we do not need lowerTick and upperTick 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
  1. 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.

Copy link
Member Author

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.

Comment on lines 271 to 273
if nextTick.GT(sdk.NewInt(upperTick)) {
break
}
Copy link
Member

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.

Copy link
Member Author

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

currentTick = nextTick.Int64()

totalLiquidityWithinRange := currentLiquidity
for currentTick <= upperTick {
Copy link
Member

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:

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

Copy link
Member Author

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

Copy link
Member

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 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattverse mattverse requested a review from p0mvn March 22, 2023 13:55
Copy link
Member

@p0mvn p0mvn left a 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

Comment on lines +126 to +135
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
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, addressed

Copy link
Member Author

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

Comment on lines 164 to 166
// 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) {
Copy link
Member

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Godoc revised

Comment on lines 238 to 240
keyTick := types.KeyTick(poolId, nextTick.Int64())
tickStruct := model.TickInfo{}
found, err := osmoutils.Get(store, keyTick, &tickStruct)
Copy link
Member

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed :)

@@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider unexporting

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexported


expectedLiquidityDepthForRange []query.LiquidityDepthWithRange
}{
{
Copy link
Member

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added :)

@mattverse mattverse merged commit fbf577e into main Mar 23, 2023
@mattverse mattverse deleted the mattverse/cl-liquidity-query branch March 23, 2023 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants