Skip to content

Commit

Permalink
feat[CL]: add num initialized ticks query (#6416)
Browse files Browse the repository at this point in the history
* add num initialized ticks query

* update changelog

* Generated protofile changes

* add max number of initialized ticks to return

* Generated protofile changes

* remove limit

* update query.yml

* add go test

---------

Co-authored-by: devbot-wizard <141283918+devbot-wizard@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
  • Loading branch information
3 people committed Sep 15, 2023
1 parent ad31bfb commit 9f664d7
Show file tree
Hide file tree
Showing 11 changed files with 1,225 additions and 137 deletions.
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)

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

0 comments on commit 9f664d7

Please sign in to comment.