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

feat[CL]: add num initialized ticks query #6416

Merged
merged 8 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Features

* [#6416](https://github.com/osmosis-labs/osmosis/pull/6416) feat[CL]: add num initialized ticks query

### State Breaking

* [#6344](https://github.com/osmosis-labs/osmosis/pull/6344) fix: set name, display and symbol of denom metadata in tokenfactory's CreateDenom
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
cosmossdk.io/math v1.1.2
github.com/CosmWasm/wasmd v0.31.0
github.com/cosmos/cosmos-proto v1.0.0-beta.3
github.com/cosmos/cosmos-sdk v0.47.4
github.com/cosmos/cosmos-sdk v0.47.5
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v4 v4.1.0
github.com/cosmos/ibc-apps/modules/async-icq/v4 v4.1.0
Expand Down
28 changes: 28 additions & 0 deletions proto/osmosis/concentrated-liquidity/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ service Query {
option (google.api.http).get =
"/osmosis/concentratedliquidity/v1beta1/get_total_liquidity";
}

// NumNextInitializedTicks returns the provided number of next initialized
// ticks in the direction of swapping the token in denom.
rpc NumNextInitializedTicks(NumNextInitializedTicksRequest)
returns (NumNextInitializedTicksResponse) {
option (google.api.http).get = "/osmosis/concentratedliquidity/v1beta1/"
"num_next_initialized_ticks";
}
}

//=============================== UserPositions
Expand Down Expand Up @@ -318,3 +326,23 @@ message GetTotalLiquidityResponse {
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
}

//=============================== NumNextInitializedTicks
message NumNextInitializedTicksRequest {
uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ];
string token_in_denom = 2
[ (gogoproto.moretags) = "yaml:\"token_in_denom\"" ];
uint64 num_next_initialized_ticks = 3
[ (gogoproto.moretags) = "yaml:\"num_next_initialized_ticks\"" ];
}
message NumNextInitializedTicksResponse {
repeated TickLiquidityNet liquidity_depths = 1
[ (gogoproto.nullable) = false ];
int64 current_tick = 2;
string current_liquidity = 3 [

(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.moretags) = "yaml:\"current_liquidity\"",
(gogoproto.nullable) = false
];
}
5 changes: 5 additions & 0 deletions proto/osmosis/concentrated-liquidity/query.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ queries:
query_func: "k.GetTotalLiquidity"
cli:
cmd: "GetTotalLiquidity"
NumNextInitializedTicks:
proto_wrapper:
query_func: "k.NumNextInitializedTicks"
cli:
cmd: "NumNextInitializedTicks"
10 changes: 10 additions & 0 deletions x/concentrated-liquidity/client/grpc/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ func (q Querier) Params(grpcCtx context.Context,
return q.Q.Params(ctx, *req)
}

func (q Querier) NumNextInitializedTicks(grpcCtx context.Context,
req *queryproto.NumNextInitializedTicksRequest,
) (*queryproto.NumNextInitializedTicksResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(grpcCtx)
return q.Q.NumNextInitializedTicks(ctx, *req)
}

func (q Querier) LiquidityPerTickRange(grpcCtx context.Context,
req *queryproto.LiquidityPerTickRangeRequest,
) (*queryproto.LiquidityPerTickRangeResponse, error) {
Expand Down
25 changes: 25 additions & 0 deletions x/concentrated-liquidity/client/query_proto_wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,28 @@ func (q Querier) GetTotalLiquidity(ctx sdk.Context, req clquery.GetTotalLiquidit
TotalLiquidity: totalLiquidity,
}, nil
}

// NumNextInitializedTicks returns an array of LiquidityDepthWithRange, which contains the user defined number of next initialized ticks in the direction
// of swapping in the given tokenInDenom.
func (q Querier) NumNextInitializedTicks(ctx sdk.Context, req clquery.NumNextInitializedTicksRequest) (*clquery.NumNextInitializedTicksResponse, error) {
if req.TokenInDenom == "" {
return nil, status.Error(codes.InvalidArgument, "tokenIn is empty")
}

liquidityDepths, err := q.Keeper.GetNumNextInitializedTicks(
ctx,
req.PoolId,
req.NumNextInitializedTicks,
req.TokenInDenom,
)
if err != nil {
return nil, err
}

pool, err := q.Keeper.GetConcentratedPoolById(ctx, req.PoolId)
if err != nil {
return nil, err
}

return &clquery.NumNextInitializedTicksResponse{LiquidityDepths: liquidityDepths, CurrentLiquidity: pool.GetLiquidity(), CurrentTick: pool.GetCurrentTick()}, nil
}
823 changes: 687 additions & 136 deletions x/concentrated-liquidity/client/queryproto/query.pb.go

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions x/concentrated-liquidity/client/queryproto/query.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions x/concentrated-liquidity/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,95 @@ func (k Keeper) getTickByTickIndex(ctx sdk.Context, poolId uint64, tickIndex int
}
return tickStruct, nil
}

// GetNumNextInitializedTicks is a method that returns an array of TickLiquidityNet objects representing the net liquidity in the direction of swapping the given token in
// for a given pool. The number of ticks returned is determined by the numberOfNextInitializedTicks parameter.
func (k Keeper) GetNumNextInitializedTicks(ctx sdk.Context, poolId, numberOfNextInitializedTicks uint64, tokenInDenom string) ([]queryproto.TickLiquidityNet, error) {
p, err := k.getPoolById(ctx, poolId)
if err != nil {
return []queryproto.TickLiquidityNet{}, err
}

startTick := p.GetCurrentTick()

// sanity check that given tokenIn is an asset in pool.
if tokenInDenom != p.GetToken0() && tokenInDenom != p.GetToken1() {
return []queryproto.TickLiquidityNet{}, types.TokenInDenomNotInPoolError{TokenInDenom: tokenInDenom}
}

// figure out zero for one depending on the token in.
zeroForOne := p.GetToken0() == tokenInDenom

ctx.Logger().Debug(fmt.Sprintf("is_zero_for_one %t\n", zeroForOne))

// the boundTick will always be the min and max tick depending on the swap direction.
// we can narrow this down later to some max number of ticks to iterate through.
ctx.Logger().Debug(fmt.Sprintf("min_tick %d\n", types.MinInitializedTick))
ctx.Logger().Debug(fmt.Sprintf("max_tick %d\n", types.MaxTick))

var boundTick osmomath.Int
if boundTick.IsNil() {
if zeroForOne {
boundTick = osmomath.NewInt(types.MinInitializedTick)
} else {
boundTick = osmomath.NewInt(types.MaxTick)
}
}

currentTickSqrtPrice, err := math.TickToSqrtPrice(startTick)
if err != nil {
return []queryproto.TickLiquidityNet{}, err
}

ctx.Logger().Debug(fmt.Sprintf("currentTick %d; current tick's sqrt price%s\n", startTick, currentTickSqrtPrice))

// iterator assignments
store := ctx.KVStore(k.storeKey)
prefixBz := types.KeyTickPrefixByPoolId(poolId)
prefixStore := prefix.NewStore(store, prefixBz)

// If zero for one, we use reverse iterator. As a result, we need to increment the start tick by 1
// so that we include the start tick in the search.
//
// If one for zero, we use forward iterator. However, our definition of the active range is inclusive
// of the lower bound. As a result, current liquidity must already include the lower bound tick
// so we skip it.
startTick = startTick + 1

startTickKey := types.TickIndexToBytes(startTick)
boundTickKey := types.TickIndexToBytes(boundTick.Int64())

// define iterator depending on swap strategy
var iterator db.Iterator
if zeroForOne {
iterator = prefixStore.ReverseIterator(boundTickKey, startTickKey)
} else {
iterator = prefixStore.Iterator(startTickKey, storetypes.InclusiveEndBytes(boundTickKey))
}

liquidityDepths := []queryproto.TickLiquidityNet{}

iterationCount := uint64(0)
Copy link
Member

Choose a reason for hiding this comment

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

Is this still needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, iterationCount refers to the user provided literation limit

Copy link
Member

Choose a reason for hiding this comment

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

Ah right, mistook this for the Go-side limit we discussed before


defer iterator.Close()
for ; iterator.Valid() && iterationCount < numberOfNextInitializedTicks; iterator.Next() {
tickIndex, err := types.TickIndexFromBytes(iterator.Key())
if err != nil {
return []queryproto.TickLiquidityNet{}, err
}

tickStruct, err := ParseTickFromBz(iterator.Value())
if err != nil {
return []queryproto.TickLiquidityNet{}, err
}

liquidityDepth := queryproto.TickLiquidityNet{
LiquidityNet: tickStruct.LiquidityNet,
TickIndex: tickIndex,
}
liquidityDepths = append(liquidityDepths, liquidityDepth)
iterationCount++
}

return liquidityDepths, nil
}
Loading