From 3a9d8f891fe0d7f48ff7134ee081c05b620e0708 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 25 Sep 2023 01:21:56 +0700 Subject: [PATCH 01/13] add new query --- .../concentrated-liquidity/query.proto | 24 + .../client/grpc/grpc_query.go | 10 + .../client/query_proto_wrap.go | 9 + .../client/queryproto/query.pb.go | 779 ++++++++++++++---- .../client/queryproto/query.pb.gw.go | 83 ++ x/concentrated-liquidity/query.go | 62 ++ 6 files changed, 825 insertions(+), 142 deletions(-) diff --git a/proto/osmosis/concentrated-liquidity/query.proto b/proto/osmosis/concentrated-liquidity/query.proto index 9d499e3be48..12df9b3899b 100644 --- a/proto/osmosis/concentrated-liquidity/query.proto +++ b/proto/osmosis/concentrated-liquidity/query.proto @@ -132,6 +132,13 @@ service Query { option (google.api.http).get = "/osmosis/concentratedliquidity/v1beta1/" "num_next_initialized_ticks"; } + + // TickRangeUnderlyingAssets returns uderlying asset of a tick range + rpc TickRangeUnderlyingAssets(TickRangeUnderlyingAssetsRequest) + returns (TickRangeUnderlyingAssetsResponse) { + option (google.api.http).get = "/osmosis/concentratedliquidity/v1beta1/" + "tick_range_underlying_assets"; + } } //=============================== UserPositions @@ -345,4 +352,21 @@ message NumNextInitializedTicksResponse { (gogoproto.moretags) = "yaml:\"current_liquidity\"", (gogoproto.nullable) = false ]; +} + +////=============================== TickRangeUnderlyingAssets +message TickRangeUnderlyingAssetsRequest { + uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; + int64 lower_tick = 2 [ (gogoproto.moretags) = "yaml:\"lower_tick\"" ]; + int64 upper_tick = 3 [ (gogoproto.moretags) = "yaml:\"upper_tick\"" ]; +} +message TickRangeUnderlyingAssetsResponse { + cosmos.base.v1beta1.Coin token0 = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin" + ]; + cosmos.base.v1beta1.Coin token1 = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin" + ]; } \ No newline at end of file diff --git a/x/concentrated-liquidity/client/grpc/grpc_query.go b/x/concentrated-liquidity/client/grpc/grpc_query.go index 0b3fd0fc4b5..fbafec955c9 100644 --- a/x/concentrated-liquidity/client/grpc/grpc_query.go +++ b/x/concentrated-liquidity/client/grpc/grpc_query.go @@ -170,3 +170,13 @@ func (q Querier) CFMMPoolIdLinkFromConcentratedPoolId(grpcCtx context.Context, return q.Q.CFMMPoolIdLinkFromConcentratedPoolId(ctx, *req) } +func (q Querier) TickRangeUnderlyingAssets(grpcCtx context.Context, + req *queryproto.TickRangeUnderlyingAssetsRequest, +) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.TickRangeUnderlyingAssets(ctx, *req) +} + diff --git a/x/concentrated-liquidity/client/query_proto_wrap.go b/x/concentrated-liquidity/client/query_proto_wrap.go index cf62b33d2d3..a7396bfc15b 100644 --- a/x/concentrated-liquidity/client/query_proto_wrap.go +++ b/x/concentrated-liquidity/client/query_proto_wrap.go @@ -318,3 +318,12 @@ func (q Querier) NumNextInitializedTicks(ctx sdk.Context, req clquery.NumNextIni return &clquery.NumNextInitializedTicksResponse{LiquidityDepths: liquidityDepths, CurrentLiquidity: pool.GetLiquidity(), CurrentTick: pool.GetCurrentTick()}, nil } + +// TickRangeUnderlyingAssets returns uderlying asset of a tick range +func (q Querier) TickRangeUnderlyingAssets(ctx sdk.Context, req clquery.TickRangeUnderlyingAssetsRequest) (*clquery.TickRangeUnderlyingAssetsResponse, error) { + if req.PoolId == 0 { + return nil, status.Error(codes.InvalidArgument, "pool id is zero") + } + + return &clquery.TickRangeUnderlyingAssetsResponse{}, nil +} diff --git a/x/concentrated-liquidity/client/queryproto/query.pb.go b/x/concentrated-liquidity/client/queryproto/query.pb.go index 2490b681750..d9ea3821903 100644 --- a/x/concentrated-liquidity/client/queryproto/query.pb.go +++ b/x/concentrated-liquidity/client/queryproto/query.pb.go @@ -1620,6 +1620,119 @@ func (m *NumNextInitializedTicksResponse) GetCurrentTick() int64 { return 0 } +// //=============================== TickRangeUnderlyingAssets +type TickRangeUnderlyingAssetsRequest struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty" yaml:"pool_id"` + LowerTick int64 `protobuf:"varint,2,opt,name=lower_tick,json=lowerTick,proto3" json:"lower_tick,omitempty" yaml:"lower_tick"` + UpperTick int64 `protobuf:"varint,3,opt,name=upper_tick,json=upperTick,proto3" json:"upper_tick,omitempty" yaml:"upper_tick"` +} + +func (m *TickRangeUnderlyingAssetsRequest) Reset() { *m = TickRangeUnderlyingAssetsRequest{} } +func (m *TickRangeUnderlyingAssetsRequest) String() string { return proto.CompactTextString(m) } +func (*TickRangeUnderlyingAssetsRequest) ProtoMessage() {} +func (*TickRangeUnderlyingAssetsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_5c83e18b11fd607d, []int{32} +} +func (m *TickRangeUnderlyingAssetsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TickRangeUnderlyingAssetsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TickRangeUnderlyingAssetsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TickRangeUnderlyingAssetsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_TickRangeUnderlyingAssetsRequest.Merge(m, src) +} +func (m *TickRangeUnderlyingAssetsRequest) XXX_Size() int { + return m.Size() +} +func (m *TickRangeUnderlyingAssetsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_TickRangeUnderlyingAssetsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_TickRangeUnderlyingAssetsRequest proto.InternalMessageInfo + +func (m *TickRangeUnderlyingAssetsRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *TickRangeUnderlyingAssetsRequest) GetLowerTick() int64 { + if m != nil { + return m.LowerTick + } + return 0 +} + +func (m *TickRangeUnderlyingAssetsRequest) GetUpperTick() int64 { + if m != nil { + return m.UpperTick + } + return 0 +} + +type TickRangeUnderlyingAssetsResponse struct { + Token0 types2.Coin `protobuf:"bytes,1,opt,name=token0,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coin" json:"token0"` + Token1 types2.Coin `protobuf:"bytes,2,opt,name=token1,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coin" json:"token1"` +} + +func (m *TickRangeUnderlyingAssetsResponse) Reset() { *m = TickRangeUnderlyingAssetsResponse{} } +func (m *TickRangeUnderlyingAssetsResponse) String() string { return proto.CompactTextString(m) } +func (*TickRangeUnderlyingAssetsResponse) ProtoMessage() {} +func (*TickRangeUnderlyingAssetsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5c83e18b11fd607d, []int{33} +} +func (m *TickRangeUnderlyingAssetsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TickRangeUnderlyingAssetsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TickRangeUnderlyingAssetsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TickRangeUnderlyingAssetsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TickRangeUnderlyingAssetsResponse.Merge(m, src) +} +func (m *TickRangeUnderlyingAssetsResponse) XXX_Size() int { + return m.Size() +} +func (m *TickRangeUnderlyingAssetsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TickRangeUnderlyingAssetsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TickRangeUnderlyingAssetsResponse proto.InternalMessageInfo + +func (m *TickRangeUnderlyingAssetsResponse) GetToken0() types2.Coin { + if m != nil { + return m.Token0 + } + return types2.Coin{} +} + +func (m *TickRangeUnderlyingAssetsResponse) GetToken1() types2.Coin { + if m != nil { + return m.Token1 + } + return types2.Coin{} +} + func init() { proto.RegisterType((*UserPositionsRequest)(nil), "osmosis.concentratedliquidity.v1beta1.UserPositionsRequest") proto.RegisterType((*UserPositionsResponse)(nil), "osmosis.concentratedliquidity.v1beta1.UserPositionsResponse") @@ -1653,6 +1766,8 @@ func init() { proto.RegisterType((*GetTotalLiquidityResponse)(nil), "osmosis.concentratedliquidity.v1beta1.GetTotalLiquidityResponse") proto.RegisterType((*NumNextInitializedTicksRequest)(nil), "osmosis.concentratedliquidity.v1beta1.NumNextInitializedTicksRequest") proto.RegisterType((*NumNextInitializedTicksResponse)(nil), "osmosis.concentratedliquidity.v1beta1.NumNextInitializedTicksResponse") + proto.RegisterType((*TickRangeUnderlyingAssetsRequest)(nil), "osmosis.concentratedliquidity.v1beta1.TickRangeUnderlyingAssetsRequest") + proto.RegisterType((*TickRangeUnderlyingAssetsResponse)(nil), "osmosis.concentratedliquidity.v1beta1.TickRangeUnderlyingAssetsResponse") } func init() { @@ -1660,149 +1775,156 @@ func init() { } var fileDescriptor_5c83e18b11fd607d = []byte{ - // 2264 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4d, 0x6c, 0x1c, 0x49, - 0x15, 0x4e, 0x4f, 0x7e, 0xe7, 0xc5, 0xf9, 0x2b, 0x3b, 0xb6, 0x33, 0x49, 0x66, 0xb2, 0x05, 0x61, - 0xad, 0x4d, 0x3c, 0x43, 0xfe, 0x08, 0x89, 0x93, 0xcd, 0x7a, 0xec, 0xb5, 0x35, 0x5a, 0xc7, 0xeb, - 0xf4, 0xc6, 0x80, 0x38, 0xd0, 0xdb, 0xd3, 0x5d, 0x1e, 0x97, 0xa6, 0xa7, 0x6b, 0xd2, 0x5d, 0x6d, + // 2369 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x4d, 0x6c, 0x1c, 0x49, + 0x15, 0x4e, 0x39, 0x89, 0x37, 0xf3, 0xe2, 0xfc, 0x95, 0x1d, 0xdb, 0x99, 0x24, 0x33, 0x49, 0x41, + 0x88, 0xb5, 0x89, 0x67, 0x36, 0x7f, 0x84, 0xfc, 0x6d, 0xd6, 0x63, 0xc7, 0x66, 0x14, 0xc7, 0xeb, + 0xf4, 0xc6, 0x80, 0x38, 0xd0, 0xdb, 0xd3, 0x5d, 0x1e, 0xb7, 0xa6, 0xa7, 0x6b, 0xd2, 0x5d, 0x1d, 0xc7, 0x2c, 0x91, 0x56, 0xec, 0x11, 0x09, 0x16, 0x71, 0x45, 0x5c, 0xb8, 0xa0, 0x15, 0x47, 0x2e, - 0x70, 0x83, 0x03, 0x8a, 0x38, 0xac, 0x56, 0x42, 0x48, 0x68, 0x0f, 0xb3, 0x90, 0x70, 0x40, 0x5a, - 0x40, 0x62, 0xb8, 0x70, 0x44, 0x5d, 0x5d, 0xdd, 0xd3, 0x33, 0xee, 0xb1, 0x7b, 0xc6, 0xe6, 0xb4, - 0xa7, 0x4c, 0xf5, 0xfb, 0xfd, 0xde, 0x7b, 0xf5, 0xaa, 0x5e, 0x39, 0xf0, 0x1a, 0x73, 0x1b, 0xcc, - 0xa5, 0x6e, 0xc9, 0x60, 0xb6, 0x41, 0x6c, 0xee, 0xe8, 0x9c, 0x98, 0xd3, 0x16, 0x7d, 0xe2, 0x51, - 0x93, 0xf2, 0xad, 0xd2, 0x13, 0x8f, 0x38, 0x5b, 0xc5, 0xa6, 0xc3, 0x38, 0x43, 0x97, 0x25, 0x6f, - 0x31, 0xce, 0x1b, 0xb1, 0x16, 0x37, 0xae, 0x55, 0x09, 0xd7, 0xaf, 0xe5, 0xc6, 0x6a, 0xac, 0xc6, - 0x84, 0x44, 0xc9, 0xff, 0x15, 0x08, 0xe7, 0xae, 0xec, 0x62, 0xa8, 0xa9, 0x3b, 0x7a, 0xc3, 0x95, - 0xcc, 0xd3, 0xbb, 0x30, 0x73, 0x6a, 0xd4, 0x2b, 0xf6, 0x5a, 0xa8, 0x3b, 0x6f, 0x08, 0xfe, 0x52, - 0x55, 0x77, 0x49, 0x49, 0xba, 0x51, 0x32, 0x18, 0xb5, 0x25, 0xfd, 0xb5, 0x38, 0x5d, 0x20, 0x8a, - 0xb8, 0x9a, 0x7a, 0x8d, 0xda, 0x3a, 0xa7, 0x2c, 0xe4, 0xbd, 0x50, 0x63, 0xac, 0x66, 0x91, 0x92, - 0xde, 0xa4, 0x25, 0xdd, 0xb6, 0x19, 0x17, 0xc4, 0xd0, 0xb1, 0x73, 0x92, 0x2a, 0x56, 0x55, 0x6f, - 0xad, 0xa4, 0xdb, 0x5b, 0x21, 0x29, 0x30, 0xa2, 0x05, 0xc8, 0x83, 0x85, 0x24, 0x15, 0x7a, 0xa5, - 0x38, 0x6d, 0x10, 0x97, 0xeb, 0x8d, 0x66, 0x08, 0xa0, 0x97, 0xc1, 0xf4, 0x9c, 0xb8, 0x53, 0xbb, - 0xc5, 0xa3, 0xc9, 0x5c, 0x1a, 0x63, 0xbf, 0xb5, 0x0b, 0x3b, 0x15, 0x5f, 0xe9, 0x06, 0xd1, 0x1c, - 0x62, 0x30, 0xc7, 0x0c, 0xc4, 0xf0, 0xaf, 0x15, 0x18, 0x5b, 0x75, 0x89, 0xb3, 0x22, 0xb5, 0xb9, - 0x2a, 0x79, 0xe2, 0x11, 0x97, 0xa3, 0xab, 0x70, 0x54, 0x37, 0x4d, 0x87, 0xb8, 0xee, 0xa4, 0x72, - 0x49, 0x99, 0xca, 0x96, 0x51, 0xbb, 0x55, 0x38, 0xb9, 0xa5, 0x37, 0xac, 0xbb, 0x58, 0x12, 0xb0, - 0x1a, 0xb2, 0xa0, 0x2b, 0x70, 0xb4, 0xc9, 0x98, 0xa5, 0x51, 0x73, 0x32, 0x73, 0x49, 0x99, 0x3a, - 0x14, 0xe7, 0x96, 0x04, 0xac, 0x1e, 0xf1, 0x7f, 0x55, 0x4c, 0xb4, 0x00, 0xd0, 0x49, 0xc1, 0xe4, - 0xc1, 0x4b, 0xca, 0xd4, 0xf1, 0xeb, 0x5f, 0x29, 0xca, 0xe8, 0xf9, 0xf9, 0x2a, 0x06, 0x15, 0x28, - 0xf3, 0x55, 0x5c, 0xd1, 0x6b, 0x44, 0xba, 0xa5, 0xc6, 0x24, 0xf1, 0xef, 0x14, 0x38, 0xdb, 0xe3, - 0xbb, 0xdb, 0x64, 0xb6, 0x4b, 0xd0, 0xbb, 0x90, 0x0d, 0xc3, 0xe3, 0xbb, 0x7f, 0x70, 0xea, 0xf8, - 0xf5, 0x7b, 0xc5, 0x54, 0x95, 0x5c, 0x5c, 0xf0, 0x2c, 0x2b, 0x54, 0x58, 0x76, 0x88, 0x5e, 0x37, - 0xd9, 0xa6, 0x5d, 0x3e, 0xf4, 0xbc, 0x55, 0x38, 0xa0, 0x76, 0x94, 0xa2, 0xc5, 0x2e, 0x0c, 0x19, - 0x81, 0xe1, 0xd5, 0x5d, 0x31, 0x04, 0xee, 0x75, 0x81, 0x58, 0x86, 0xd1, 0xc8, 0xdc, 0x56, 0xc5, - 0x0c, 0xc3, 0x7f, 0x1b, 0x8e, 0x87, 0xc6, 0xfc, 0xa0, 0x2a, 0x22, 0xa8, 0xe3, 0xed, 0x56, 0x01, - 0x85, 0x41, 0x8d, 0x88, 0x58, 0x85, 0x70, 0x55, 0x31, 0xf1, 0x06, 0x8c, 0x75, 0xeb, 0x93, 0x21, - 0xf9, 0x0e, 0x1c, 0x0b, 0xb9, 0x84, 0xb6, 0xfd, 0x89, 0x48, 0xa4, 0x13, 0x7f, 0x03, 0x46, 0x56, - 0x18, 0xb3, 0xa2, 0xfa, 0x59, 0x48, 0x08, 0xd0, 0x30, 0x49, 0xfe, 0x91, 0x02, 0x27, 0xa4, 0x62, - 0x89, 0xe4, 0x16, 0x1c, 0xf6, 0x0b, 0x29, 0x4c, 0xec, 0x58, 0x31, 0xd8, 0x48, 0xc5, 0x70, 0x23, - 0x15, 0x67, 0xed, 0xad, 0x72, 0xf6, 0x0f, 0xbf, 0x9a, 0x3e, 0xec, 0xcb, 0x55, 0xd4, 0x80, 0x7b, - 0xff, 0x32, 0x76, 0x0a, 0x4e, 0xac, 0x88, 0xc6, 0x25, 0xdd, 0xc5, 0xab, 0x70, 0x32, 0xfc, 0x20, - 0x5d, 0x9c, 0x83, 0x23, 0x41, 0x6f, 0x93, 0xa1, 0xbe, 0xbc, 0x4b, 0xa8, 0x03, 0x71, 0x19, 0x53, - 0x29, 0x8a, 0x3f, 0x52, 0xe0, 0xf4, 0x63, 0x6a, 0xd4, 0x97, 0x42, 0xb6, 0x65, 0xc2, 0xd1, 0xbb, - 0x70, 0x22, 0x12, 0xd3, 0x6c, 0xc2, 0xe5, 0xe6, 0x9c, 0xf1, 0x25, 0x3f, 0x6d, 0x15, 0xce, 0x07, - 0x78, 0x5c, 0xb3, 0x5e, 0xa4, 0xac, 0xd4, 0xd0, 0xf9, 0x7a, 0x71, 0x89, 0xd4, 0x74, 0x63, 0x6b, - 0x9e, 0x18, 0xed, 0x56, 0x61, 0x2c, 0x28, 0x9e, 0x2e, 0x0d, 0x58, 0x1d, 0xb1, 0xe2, 0x16, 0x6e, - 0x02, 0xf8, 0xad, 0x56, 0xa3, 0xb6, 0x49, 0x9e, 0x8a, 0x38, 0x1d, 0x2c, 0x9f, 0x6d, 0xb7, 0x0a, - 0x67, 0x02, 0xd9, 0x0e, 0x0d, 0xab, 0xd9, 0xa0, 0x27, 0xfb, 0xbf, 0xff, 0xa9, 0xc0, 0x44, 0xe4, - 0xe8, 0x3c, 0x69, 0xf2, 0xf5, 0x6f, 0x52, 0xbe, 0xae, 0xea, 0x76, 0x8d, 0xa0, 0x35, 0x38, 0xdd, - 0xb1, 0xa8, 0x37, 0x98, 0x67, 0xef, 0x8b, 0xdb, 0xa7, 0xa2, 0xf5, 0xac, 0xd0, 0xe9, 0x7b, 0x6e, - 0xb1, 0x4d, 0xe2, 0x68, 0xbe, 0x5b, 0xdb, 0x3d, 0xef, 0xd0, 0xb0, 0x9a, 0x15, 0x0b, 0x3f, 0xba, - 0xbe, 0x94, 0xd7, 0x6c, 0x86, 0x52, 0x07, 0x7b, 0xa5, 0x3a, 0x34, 0xac, 0x66, 0xc5, 0xc2, 0x97, - 0xc2, 0x9f, 0x65, 0x20, 0x1f, 0x4f, 0x4c, 0xc5, 0x9e, 0xa7, 0x0e, 0x31, 0xfc, 0x02, 0x09, 0x77, - 0x40, 0xac, 0x27, 0x2a, 0xbb, 0xf6, 0xc4, 0x22, 0x1c, 0xe3, 0xac, 0x4e, 0x6c, 0x8d, 0x06, 0xb5, - 0x99, 0x2d, 0x8f, 0xb6, 0x5b, 0x85, 0x53, 0x32, 0xe6, 0x92, 0x82, 0xd5, 0xa3, 0xe2, 0x67, 0xc5, - 0xf6, 0xbd, 0x76, 0xb9, 0xee, 0xf0, 0x3e, 0x5e, 0x77, 0x68, 0x58, 0xcd, 0x8a, 0x85, 0xc0, 0x7a, - 0x07, 0x46, 0x3c, 0x97, 0x68, 0x86, 0x27, 0xd1, 0x1e, 0xba, 0xa4, 0x4c, 0x1d, 0x2b, 0x4f, 0xb4, - 0x5b, 0x85, 0x51, 0x89, 0x36, 0x46, 0xc5, 0x2a, 0x78, 0x2e, 0x99, 0xf3, 0xa2, 0x30, 0x55, 0x99, - 0x67, 0x9b, 0x81, 0xe0, 0xe1, 0x5e, 0x83, 0x1d, 0x1a, 0x56, 0xb3, 0x62, 0x11, 0x37, 0x68, 0x33, - 0x4d, 0x7c, 0x9b, 0x3c, 0x92, 0x64, 0x30, 0xa4, 0x06, 0x06, 0x97, 0x59, 0x59, 0x2c, 0x7e, 0x9a, - 0x81, 0x42, 0xdf, 0x08, 0xcb, 0x7d, 0xb6, 0x1e, 0xaf, 0x2c, 0xd3, 0xaf, 0xba, 0xb0, 0x2b, 0xdc, - 0x4e, 0xd9, 0xdc, 0x7a, 0x37, 0x98, 0xdc, 0x83, 0x9d, 0xda, 0x12, 0xb5, 0xec, 0xa2, 0x57, 0x60, - 0xc4, 0xf0, 0x1c, 0x87, 0xd8, 0x3c, 0x56, 0x5d, 0xea, 0x71, 0xf9, 0x4d, 0x60, 0xb5, 0xe0, 0x4c, - 0xc8, 0x12, 0x49, 0x8b, 0xcc, 0x64, 0xcb, 0x0f, 0xd2, 0xd5, 0xf9, 0x64, 0x10, 0x93, 0x6d, 0x5a, - 0xb0, 0x7a, 0x5a, 0x7e, 0x8b, 0x5c, 0xc5, 0x6f, 0xc1, 0x85, 0x68, 0xb1, 0x12, 0x14, 0xa5, 0xd8, - 0x6d, 0xc3, 0x54, 0x1f, 0xfe, 0x40, 0x81, 0x8b, 0x7d, 0xb4, 0xc9, 0x48, 0x57, 0x21, 0xdb, 0x01, - 0x15, 0x84, 0xf8, 0xf5, 0x94, 0x21, 0xee, 0xd3, 0x16, 0xc2, 0x33, 0xb5, 0x83, 0xf2, 0x5b, 0x70, - 0x71, 0xce, 0xd2, 0x69, 0x43, 0xaf, 0x5a, 0xe4, 0x9d, 0xa6, 0x43, 0x74, 0x53, 0x25, 0x9b, 0xba, - 0x63, 0xba, 0x7b, 0x3e, 0x14, 0x7f, 0xa6, 0x40, 0xbe, 0x9f, 0x6a, 0x09, 0xf0, 0x7b, 0x30, 0x69, - 0x84, 0x1c, 0x9a, 0x2b, 0x58, 0x34, 0x27, 0xe0, 0x91, 0x78, 0xcf, 0x75, 0x1d, 0x16, 0x21, 0xba, - 0x39, 0x46, 0xed, 0xf2, 0xab, 0x3e, 0x94, 0x76, 0xab, 0x50, 0x90, 0x09, 0xec, 0xa3, 0x08, 0xab, - 0xe3, 0x46, 0xa2, 0x17, 0x78, 0x15, 0x72, 0x91, 0x7f, 0x95, 0xf0, 0xa6, 0xb6, 0x77, 0xdc, 0x1f, - 0x64, 0xe0, 0x7c, 0xa2, 0x5e, 0x09, 0xfa, 0x09, 0x8c, 0x75, 0x7c, 0x8d, 0x6e, 0x88, 0x29, 0x00, - 0x7f, 0x49, 0x02, 0x3e, 0xdf, 0x0b, 0xb8, 0xa3, 0x04, 0xab, 0xa3, 0xc6, 0x76, 0xd3, 0xbe, 0xc9, - 0x35, 0xe6, 0xac, 0x11, 0xca, 0x89, 0x19, 0x37, 0x99, 0x19, 0xd0, 0x64, 0x92, 0x12, 0xac, 0x8e, - 0x46, 0x9f, 0x3b, 0x26, 0xf1, 0x12, 0x5c, 0xf4, 0x6f, 0x02, 0xb3, 0x86, 0xe1, 0x35, 0x3c, 0x4b, - 0xe7, 0xcc, 0xe9, 0xa9, 0xab, 0x81, 0xf6, 0xca, 0x6f, 0x33, 0x90, 0xef, 0xa7, 0x4e, 0x86, 0xf5, - 0x43, 0x05, 0xce, 0x77, 0x65, 0x5e, 0xab, 0x39, 0x6c, 0x93, 0xaf, 0x6b, 0x35, 0x8b, 0x55, 0x75, - 0x4b, 0x86, 0xf7, 0x42, 0x22, 0xd6, 0x79, 0x62, 0x08, 0xb8, 0x37, 0x7c, 0xb8, 0x1f, 0x7d, 0x56, - 0xb8, 0x52, 0xa3, 0x7c, 0xdd, 0xab, 0x16, 0x0d, 0xd6, 0x90, 0x03, 0x86, 0xfc, 0x67, 0xda, 0x35, - 0xeb, 0x25, 0xbe, 0xd5, 0x24, 0x6e, 0x28, 0xe3, 0xaa, 0x93, 0x6e, 0xac, 0xaa, 0x16, 0x85, 0xcd, - 0x45, 0x61, 0x12, 0xfd, 0x40, 0x81, 0x31, 0xaf, 0xe9, 0xcf, 0x20, 0x3d, 0xbe, 0x04, 0x71, 0xbf, - 0x99, 0x72, 0x2f, 0xaf, 0x0a, 0x15, 0x8f, 0x1d, 0xdd, 0xa8, 0x13, 0xa7, 0x37, 0x25, 0x49, 0xfa, - 0xb1, 0x8a, 0x82, 0xcf, 0x71, 0x6f, 0xfc, 0x7e, 0x93, 0xf7, 0x7b, 0x4c, 0x2c, 0x86, 0x52, 0xe7, - 0x50, 0x39, 0x19, 0xf2, 0xce, 0xf2, 0x79, 0x06, 0x0a, 0x7d, 0xbd, 0x90, 0xa9, 0x7c, 0xae, 0xc0, - 0x9d, 0xc4, 0x54, 0xb2, 0xa6, 0xd8, 0x67, 0x44, 0x33, 0xc3, 0x53, 0x49, 0x63, 0x6b, 0x9a, 0xa5, - 0xbb, 0x5c, 0xe3, 0x8e, 0xbe, 0x41, 0x1c, 0xf7, 0xff, 0x99, 0xe8, 0xeb, 0xdb, 0x13, 0xfd, 0xb6, - 0x74, 0x28, 0x3a, 0x25, 0xdf, 0x5e, 0x5b, 0xd2, 0x5d, 0xfe, 0x38, 0x74, 0x06, 0x3d, 0x83, 0x53, - 0x32, 0x43, 0x5c, 0xa2, 0xdc, 0x53, 0xf2, 0xf3, 0x32, 0xf9, 0xe3, 0x5d, 0xc9, 0x0f, 0x55, 0x63, - 0xf5, 0xa4, 0x17, 0x67, 0x77, 0xf1, 0x0f, 0x15, 0x98, 0x88, 0x36, 0xa5, 0x2a, 0x66, 0xd0, 0xe1, - 0x92, 0xbd, 0x5f, 0x93, 0xc5, 0xc7, 0x0a, 0x4c, 0x6e, 0x77, 0x48, 0xe6, 0x9d, 0xc2, 0x99, 0xde, - 0x89, 0x39, 0x6c, 0x8b, 0x5f, 0x4b, 0x19, 0xae, 0x1e, 0xdd, 0xf2, 0xbc, 0x3b, 0x4d, 0x7b, 0x4c, - 0xee, 0xdf, 0x60, 0xf2, 0xbe, 0x02, 0x57, 0xe6, 0x16, 0x1e, 0x3e, 0x14, 0x63, 0x8f, 0xb9, 0x44, - 0xed, 0xfa, 0x82, 0xc3, 0x1a, 0x73, 0x31, 0x27, 0x03, 0x4a, 0x18, 0xf5, 0x47, 0x30, 0x16, 0x47, - 0xa0, 0x75, 0xa7, 0xa0, 0x10, 0x6b, 0xef, 0x09, 0x5c, 0x58, 0x45, 0xc6, 0x36, 0xcd, 0x98, 0xc2, - 0xd5, 0x74, 0x1e, 0xc8, 0x30, 0xdf, 0x81, 0x11, 0x63, 0xad, 0xd1, 0xe8, 0x31, 0x1d, 0xbb, 0x1f, - 0xc6, 0xa9, 0x58, 0x05, 0x7f, 0x29, 0x4d, 0x3d, 0x84, 0x8b, 0xfe, 0xf0, 0xbf, 0x6a, 0x57, 0x99, - 0x6d, 0x52, 0xbb, 0xb6, 0xb7, 0x17, 0x0c, 0xfc, 0x73, 0x05, 0xf2, 0xfd, 0xf4, 0x49, 0x67, 0xdf, - 0x57, 0x20, 0x17, 0xbd, 0x00, 0x68, 0x9b, 0x94, 0xaf, 0x6b, 0x4d, 0xe2, 0x50, 0x66, 0x6a, 0x16, - 0x33, 0xea, 0xb2, 0x3a, 0xee, 0xa7, 0xac, 0x8e, 0x50, 0xbd, 0x7f, 0x1f, 0x5a, 0x11, 0x5a, 0x96, - 0x98, 0x51, 0x97, 0x45, 0x32, 0x11, 0x99, 0xe9, 0x26, 0xe3, 0x1c, 0x4c, 0x2e, 0x12, 0xfe, 0x98, - 0x71, 0xdd, 0x8a, 0xae, 0x55, 0xe1, 0x18, 0xfa, 0x63, 0x05, 0xce, 0x25, 0x10, 0xa5, 0xf3, 0x1c, - 0x4e, 0x71, 0x9f, 0xa2, 0xf5, 0x5e, 0xe3, 0x76, 0x38, 0x72, 0xbf, 0x2a, 0x5b, 0xd3, 0x54, 0x8a, - 0xd6, 0x14, 0xf4, 0xa5, 0x93, 0xbc, 0xcb, 0x3a, 0x6e, 0x2b, 0x90, 0x5f, 0xf6, 0x1a, 0xcb, 0xe4, - 0x29, 0xaf, 0xd8, 0x94, 0x53, 0xdd, 0xa2, 0xdf, 0x25, 0x62, 0x34, 0x18, 0x6e, 0xef, 0x3f, 0x80, - 0x93, 0xe1, 0x30, 0xa4, 0x99, 0xc4, 0x66, 0x0d, 0x39, 0x2c, 0x9d, 0x6b, 0xb7, 0x0a, 0x67, 0xbb, - 0x87, 0xa5, 0x80, 0x8e, 0xd5, 0x11, 0x39, 0x32, 0xcd, 0xfb, 0x4b, 0x54, 0x85, 0x9c, 0xed, 0x35, - 0x34, 0x9b, 0x3c, 0xe5, 0x1a, 0xed, 0x78, 0x24, 0x2e, 0xf5, 0xae, 0xb8, 0xad, 0x1f, 0x2a, 0x5f, - 0x6e, 0xb7, 0x0a, 0xaf, 0x04, 0xca, 0xfa, 0xf3, 0x62, 0x75, 0xc2, 0x4e, 0x06, 0x26, 0x26, 0x97, - 0xbe, 0xa0, 0xbf, 0xf0, 0x93, 0xcb, 0xf5, 0x7f, 0xe7, 0xe0, 0xf0, 0x23, 0xbf, 0xa3, 0xa1, 0x5f, - 0x28, 0x20, 0xde, 0x68, 0x5c, 0x74, 0x23, 0xf5, 0xae, 0xe9, 0x3c, 0x31, 0xe5, 0x6e, 0x0e, 0x26, - 0x14, 0x44, 0x1e, 0xdf, 0xfc, 0xfe, 0x1f, 0xff, 0xf6, 0x93, 0x4c, 0x11, 0x5d, 0x2d, 0x25, 0xbd, - 0x98, 0x76, 0x1e, 0x4c, 0xa3, 0xd7, 0x62, 0xe1, 0xe0, 0x2f, 0x15, 0x38, 0x12, 0xbc, 0xd2, 0xa0, - 0xd4, 0x66, 0xe3, 0x8f, 0x44, 0xb9, 0x5b, 0x03, 0x4a, 0x49, 0x6f, 0x6f, 0x09, 0x6f, 0x4b, 0x68, - 0x3a, 0xad, 0xb7, 0x81, 0x8f, 0x1f, 0x2b, 0x70, 0xa2, 0xeb, 0x69, 0x14, 0xcd, 0xa4, 0x3d, 0xe4, - 0x13, 0x1e, 0x83, 0x73, 0xf7, 0x86, 0x13, 0x96, 0x18, 0xca, 0x02, 0xc3, 0x3d, 0x74, 0x37, 0x75, - 0xc4, 0xa5, 0x86, 0xd2, 0x7b, 0xb2, 0x3b, 0x3f, 0x43, 0x9f, 0x2b, 0x70, 0x36, 0x71, 0x42, 0x45, - 0x73, 0x83, 0x8e, 0xa1, 0x09, 0xd3, 0x72, 0x6e, 0x7e, 0x6f, 0x4a, 0x24, 0xd0, 0x45, 0x01, 0x74, - 0x16, 0x3d, 0x48, 0x09, 0xb4, 0xd3, 0x01, 0xc2, 0x37, 0x26, 0xcd, 0x11, 0x98, 0xfe, 0x13, 0x7f, - 0x4d, 0xeb, 0x7e, 0xfb, 0x40, 0x6f, 0x0e, 0xea, 0x6a, 0xe2, 0xeb, 0x54, 0x6e, 0x61, 0xaf, 0x6a, - 0x24, 0xe6, 0x8a, 0xc0, 0x3c, 0x87, 0x66, 0x07, 0xc6, 0x6c, 0x13, 0x2e, 0xda, 0x74, 0x84, 0xec, - 0x5f, 0x0a, 0x8c, 0x27, 0x4f, 0xe9, 0x28, 0x6d, 0x7e, 0x76, 0x7c, 0x3f, 0xc8, 0xbd, 0xb9, 0x47, - 0x2d, 0x43, 0xa6, 0xb9, 0xdf, 0x73, 0x00, 0xfa, 0xab, 0x02, 0xa3, 0x09, 0xe3, 0x39, 0x9a, 0x1d, - 0xd4, 0xcf, 0x6d, 0x4f, 0x06, 0xb9, 0xf2, 0x5e, 0x54, 0x48, 0x9c, 0x73, 0x02, 0xe7, 0x7d, 0x34, - 0x33, 0x30, 0xce, 0xce, 0x48, 0x8e, 0x7e, 0xaf, 0xc0, 0x48, 0xfc, 0x0f, 0x12, 0xe8, 0xee, 0x80, - 0x17, 0xa4, 0xd8, 0x5f, 0x45, 0x72, 0x33, 0x43, 0xc9, 0x4a, 0x38, 0xf7, 0x05, 0x9c, 0xdb, 0xe8, - 0xd6, 0x80, 0x6d, 0x48, 0xab, 0x6e, 0x69, 0xd4, 0x44, 0x7f, 0x57, 0x60, 0x3c, 0x79, 0xee, 0x4f, - 0x5d, 0x9d, 0x3b, 0xbe, 0x42, 0xa4, 0xae, 0xce, 0x9d, 0x1f, 0x1f, 0xf0, 0xac, 0x80, 0x39, 0x83, - 0xee, 0x0c, 0x70, 0xbe, 0x69, 0xba, 0xaf, 0x2f, 0xaa, 0xcb, 0x3f, 0x29, 0x70, 0xba, 0x77, 0x32, - 0x42, 0xaf, 0x0f, 0x37, 0xf6, 0x44, 0xf0, 0x1e, 0x0c, 0x2d, 0x2f, 0x81, 0xbd, 0x21, 0x80, 0xdd, - 0x45, 0x5f, 0x4f, 0x09, 0x6c, 0xdb, 0xfc, 0x86, 0xfe, 0xa1, 0xc0, 0x44, 0x9f, 0x81, 0x3f, 0x75, - 0x5b, 0xdd, 0xf9, 0xd9, 0x22, 0x75, 0x5b, 0xdd, 0xe5, 0xdd, 0x61, 0xe0, 0x33, 0x53, 0x1c, 0x1e, - 0x41, 0x16, 0xc3, 0x11, 0x1c, 0xfd, 0x26, 0x03, 0x5f, 0x4e, 0x33, 0x8d, 0x21, 0x35, 0x6d, 0xb3, - 0x48, 0x3f, 0x5c, 0xe6, 0xde, 0xd9, 0x57, 0x9d, 0x32, 0x2a, 0x54, 0x44, 0xc5, 0x40, 0x7a, 0xda, - 0x8e, 0x14, 0x9b, 0x1e, 0x35, 0x8b, 0xda, 0x75, 0x6d, 0xcd, 0x61, 0x0d, 0x2d, 0x2e, 0x54, 0x7a, - 0x2f, 0x69, 0xba, 0x7d, 0x86, 0xfe, 0xab, 0xc0, 0x78, 0xf2, 0x3c, 0x98, 0x7a, 0xbb, 0xef, 0x38, - 0x9e, 0xa6, 0xde, 0xee, 0x3b, 0x0f, 0xa5, 0xf8, 0x91, 0x08, 0xc9, 0x5b, 0xa8, 0x92, 0x32, 0x24, - 0x9e, 0x4b, 0x1c, 0xcd, 0x0b, 0xf5, 0x69, 0x49, 0x77, 0xad, 0x4f, 0x15, 0x38, 0xb3, 0x6d, 0x90, - 0x44, 0x69, 0xf7, 0x6f, 0xbf, 0xf9, 0x34, 0xf7, 0xc6, 0xf0, 0x0a, 0x86, 0xdc, 0x14, 0x35, 0xc2, - 0xb5, 0x9e, 0xa1, 0x57, 0x5c, 0xad, 0xfa, 0x0c, 0x67, 0xa9, 0x7b, 0xc0, 0xce, 0x13, 0x6d, 0xea, - 0x1e, 0xb0, 0xcb, 0x8c, 0x38, 0xf0, 0xd5, 0xaa, 0xff, 0xb0, 0x5a, 0x5e, 0x7f, 0xfe, 0x22, 0xaf, - 0x7c, 0xf2, 0x22, 0xaf, 0xfc, 0xe5, 0x45, 0x5e, 0xf9, 0xf0, 0x65, 0xfe, 0xc0, 0x27, 0x2f, 0xf3, - 0x07, 0xfe, 0xfc, 0x32, 0x7f, 0xe0, 0xdb, 0xcb, 0xb1, 0xd9, 0x5e, 0x9a, 0x99, 0xb6, 0xf4, 0xaa, - 0x1b, 0xd9, 0xdc, 0xb8, 0x76, 0xa7, 0xf4, 0xb4, 0xdf, 0xff, 0x2a, 0x31, 0x2c, 0x4a, 0x6c, 0x1e, - 0xfc, 0xff, 0x9a, 0xe0, 0xef, 0xef, 0x47, 0xc4, 0x3f, 0x37, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, - 0x34, 0x43, 0x3b, 0x42, 0x65, 0x24, 0x00, 0x00, + 0xc0, 0x09, 0x0e, 0x28, 0xe2, 0xb0, 0x5a, 0x09, 0x21, 0xa1, 0x3d, 0xcc, 0x42, 0xc2, 0x01, 0x29, + 0xfc, 0x48, 0xe6, 0x82, 0xc4, 0x05, 0x75, 0x75, 0x75, 0x4f, 0xcf, 0xb8, 0x67, 0xdc, 0x33, 0x36, + 0x9c, 0x38, 0x65, 0xaa, 0xeb, 0xfd, 0x7d, 0xef, 0xbd, 0x7a, 0x55, 0xef, 0xc5, 0xf0, 0x3a, 0x73, + 0xeb, 0xcc, 0x35, 0xdd, 0xa2, 0xce, 0x6c, 0x9d, 0xda, 0xdc, 0xd1, 0x38, 0x35, 0xa6, 0x2d, 0xf3, + 0xb1, 0x67, 0x1a, 0x26, 0xdf, 0x28, 0x3e, 0xf6, 0xa8, 0xb3, 0x51, 0x68, 0x38, 0x8c, 0x33, 0x7c, + 0x4e, 0xd2, 0x16, 0xe2, 0xb4, 0x11, 0x69, 0xe1, 0xc9, 0xa5, 0x0a, 0xe5, 0xda, 0xa5, 0xec, 0x58, + 0x95, 0x55, 0x99, 0xe0, 0x28, 0xfa, 0xbf, 0x02, 0xe6, 0xec, 0x85, 0x6d, 0x14, 0x35, 0x34, 0x47, + 0xab, 0xbb, 0x92, 0x78, 0x7a, 0x1b, 0x62, 0x6e, 0xea, 0xb5, 0xb2, 0xbd, 0x1a, 0xca, 0xce, 0xe9, + 0x82, 0xbe, 0x58, 0xd1, 0x5c, 0x5a, 0x94, 0x66, 0x14, 0x75, 0x66, 0xda, 0x72, 0xff, 0xf5, 0xf8, + 0xbe, 0x40, 0x14, 0x51, 0x35, 0xb4, 0xaa, 0x69, 0x6b, 0xdc, 0x64, 0x21, 0xed, 0xa9, 0x2a, 0x63, + 0x55, 0x8b, 0x16, 0xb5, 0x86, 0x59, 0xd4, 0x6c, 0x9b, 0x71, 0xb1, 0x19, 0x1a, 0x76, 0x42, 0xee, + 0x8a, 0x55, 0xc5, 0x5b, 0x2d, 0x6a, 0xf6, 0x46, 0xb8, 0x15, 0x28, 0x51, 0x03, 0xe4, 0xc1, 0x42, + 0x6e, 0xe5, 0x3b, 0xb9, 0xb8, 0x59, 0xa7, 0x2e, 0xd7, 0xea, 0x8d, 0x10, 0x40, 0x27, 0x81, 0xe1, + 0x39, 0x71, 0xa3, 0xb6, 0xf3, 0x47, 0x83, 0xb9, 0x66, 0x8c, 0xfc, 0xda, 0x36, 0xe4, 0xa6, 0xf8, + 0x6a, 0x3e, 0xa1, 0xaa, 0x43, 0x75, 0xe6, 0x18, 0x01, 0x1b, 0xf9, 0x39, 0x82, 0xb1, 0x15, 0x97, + 0x3a, 0xcb, 0x52, 0x9a, 0xab, 0xd0, 0xc7, 0x1e, 0x75, 0x39, 0xbe, 0x08, 0xaf, 0x69, 0x86, 0xe1, + 0x50, 0xd7, 0x9d, 0x44, 0x67, 0xd0, 0x54, 0xa6, 0x84, 0x37, 0x9b, 0xf9, 0xc3, 0x1b, 0x5a, 0xdd, + 0xba, 0x49, 0xe4, 0x06, 0x51, 0x42, 0x12, 0x7c, 0x01, 0x5e, 0x6b, 0x30, 0x66, 0xa9, 0xa6, 0x31, + 0x39, 0x74, 0x06, 0x4d, 0xed, 0x8b, 0x53, 0xcb, 0x0d, 0xa2, 0x0c, 0xfb, 0xbf, 0xca, 0x06, 0x9e, + 0x07, 0x68, 0x85, 0x60, 0x72, 0xef, 0x19, 0x34, 0x75, 0xf0, 0xf2, 0x17, 0x0a, 0xd2, 0x7b, 0x7e, + 0xbc, 0x0a, 0x41, 0x06, 0xca, 0x78, 0x15, 0x96, 0xb5, 0x2a, 0x95, 0x66, 0x29, 0x31, 0x4e, 0xf2, + 0x6b, 0x04, 0xc7, 0x3b, 0x6c, 0x77, 0x1b, 0xcc, 0x76, 0x29, 0x7e, 0x17, 0x32, 0xa1, 0x7b, 0x7c, + 0xf3, 0xf7, 0x4e, 0x1d, 0xbc, 0x7c, 0xbb, 0x90, 0x2a, 0x93, 0x0b, 0xf3, 0x9e, 0x65, 0x85, 0x02, + 0x4b, 0x0e, 0xd5, 0x6a, 0x06, 0x5b, 0xb7, 0x4b, 0xfb, 0x9e, 0x37, 0xf3, 0x7b, 0x94, 0x96, 0x50, + 0xbc, 0xd0, 0x86, 0x61, 0x48, 0x60, 0x38, 0xbf, 0x2d, 0x86, 0xc0, 0xbc, 0x36, 0x10, 0x4b, 0x30, + 0x1a, 0xa9, 0xdb, 0x28, 0x1b, 0xa1, 0xfb, 0xaf, 0xc3, 0xc1, 0x50, 0x99, 0xef, 0x54, 0x24, 0x9c, + 0x3a, 0xbe, 0xd9, 0xcc, 0xe3, 0xd0, 0xa9, 0xd1, 0x26, 0x51, 0x20, 0x5c, 0x95, 0x0d, 0xf2, 0x04, + 0xc6, 0xda, 0xe5, 0x49, 0x97, 0x7c, 0x03, 0x0e, 0x84, 0x54, 0x42, 0xda, 0xee, 0x78, 0x24, 0x92, + 0x49, 0xbe, 0x02, 0x23, 0xcb, 0x8c, 0x59, 0x51, 0xfe, 0xcc, 0x27, 0x38, 0x68, 0x90, 0x20, 0x7f, + 0x0f, 0xc1, 0x21, 0x29, 0x58, 0x22, 0xb9, 0x06, 0xfb, 0xfd, 0x44, 0x0a, 0x03, 0x3b, 0x56, 0x08, + 0x0e, 0x52, 0x21, 0x3c, 0x48, 0x85, 0x19, 0x7b, 0xa3, 0x94, 0xf9, 0xed, 0xcf, 0xa6, 0xf7, 0xfb, + 0x7c, 0x65, 0x25, 0xa0, 0xde, 0xbd, 0x88, 0x1d, 0x81, 0x43, 0xcb, 0xa2, 0x70, 0x49, 0x73, 0xc9, + 0x0a, 0x1c, 0x0e, 0x3f, 0x48, 0x13, 0x67, 0x61, 0x38, 0xa8, 0x6d, 0xd2, 0xd5, 0xe7, 0xb6, 0x71, + 0x75, 0xc0, 0x2e, 0x7d, 0x2a, 0x59, 0xc9, 0x47, 0x08, 0x8e, 0x3e, 0x32, 0xf5, 0xda, 0x62, 0x48, + 0xb6, 0x44, 0x39, 0x7e, 0x17, 0x0e, 0x45, 0x6c, 0xaa, 0x4d, 0xb9, 0x3c, 0x9c, 0xb7, 0x7c, 0xce, + 0x4f, 0x9b, 0xf9, 0x93, 0x01, 0x1e, 0xd7, 0xa8, 0x15, 0x4c, 0x56, 0xac, 0x6b, 0x7c, 0xad, 0xb0, + 0x48, 0xab, 0x9a, 0xbe, 0x31, 0x47, 0xf5, 0xcd, 0x66, 0x7e, 0x2c, 0x48, 0x9e, 0x36, 0x09, 0x44, + 0x19, 0xb1, 0xe2, 0x1a, 0xae, 0x02, 0xf8, 0xa5, 0x56, 0x35, 0x6d, 0x83, 0x3e, 0x15, 0x7e, 0xda, + 0x5b, 0x3a, 0xbe, 0xd9, 0xcc, 0x1f, 0x0b, 0x78, 0x5b, 0x7b, 0x44, 0xc9, 0x04, 0x35, 0xd9, 0xff, + 0xfd, 0x37, 0x04, 0x13, 0x91, 0xa1, 0x73, 0xb4, 0xc1, 0xd7, 0xbe, 0x6a, 0xf2, 0x35, 0x45, 0xb3, + 0xab, 0x14, 0xaf, 0xc2, 0xd1, 0x96, 0x46, 0xad, 0xce, 0x3c, 0x7b, 0x57, 0xcc, 0x3e, 0x12, 0xad, + 0x67, 0x84, 0x4c, 0xdf, 0x72, 0x8b, 0xad, 0x53, 0x47, 0xf5, 0xcd, 0xda, 0x6a, 0x79, 0x6b, 0x8f, + 0x28, 0x19, 0xb1, 0xf0, 0xbd, 0xeb, 0x73, 0x79, 0x8d, 0x46, 0xc8, 0xb5, 0xb7, 0x93, 0xab, 0xb5, + 0x47, 0x94, 0x8c, 0x58, 0xf8, 0x5c, 0xe4, 0xb3, 0x21, 0xc8, 0xc5, 0x03, 0x53, 0xb6, 0xe7, 0x4c, + 0x87, 0xea, 0x7e, 0x82, 0x84, 0x27, 0x20, 0x56, 0x13, 0xd1, 0xb6, 0x35, 0xb1, 0x00, 0x07, 0x38, + 0xab, 0x51, 0x5b, 0x35, 0x83, 0xdc, 0xcc, 0x94, 0x46, 0x37, 0x9b, 0xf9, 0x23, 0xd2, 0xe7, 0x72, + 0x87, 0x28, 0xaf, 0x89, 0x9f, 0x65, 0xdb, 0xb7, 0xda, 0xe5, 0x9a, 0xc3, 0xbb, 0x58, 0xdd, 0xda, + 0x23, 0x4a, 0x46, 0x2c, 0x04, 0xd6, 0x1b, 0x30, 0xe2, 0xb9, 0x54, 0xd5, 0x3d, 0x89, 0x76, 0xdf, + 0x19, 0x34, 0x75, 0xa0, 0x34, 0xb1, 0xd9, 0xcc, 0x8f, 0x4a, 0xb4, 0xb1, 0x5d, 0xa2, 0x80, 0xe7, + 0xd2, 0x59, 0x2f, 0x72, 0x53, 0x85, 0x79, 0xb6, 0x11, 0x30, 0xee, 0xef, 0x54, 0xd8, 0xda, 0x23, + 0x4a, 0x46, 0x2c, 0xe2, 0x0a, 0x6d, 0xa6, 0x8a, 0x6f, 0x93, 0xc3, 0x49, 0x0a, 0xc3, 0xdd, 0x40, + 0xe1, 0x12, 0x2b, 0x89, 0xc5, 0x0f, 0x87, 0x20, 0xdf, 0xd5, 0xc3, 0xf2, 0x9c, 0xad, 0xc5, 0x33, + 0xcb, 0xf0, 0xb3, 0x2e, 0xac, 0x0a, 0xd7, 0x53, 0x16, 0xb7, 0xce, 0x03, 0x26, 0xcf, 0x60, 0x2b, + 0xb7, 0x44, 0x2e, 0xbb, 0xf8, 0x2c, 0x8c, 0xe8, 0x9e, 0xe3, 0x50, 0x9b, 0xc7, 0xb2, 0x4b, 0x39, + 0x28, 0xbf, 0x09, 0xac, 0x16, 0x1c, 0x0b, 0x49, 0x22, 0x6e, 0x11, 0x99, 0x4c, 0xe9, 0x6e, 0xba, + 0x3c, 0x9f, 0x0c, 0x7c, 0xb2, 0x45, 0x0a, 0x51, 0x8e, 0xca, 0x6f, 0x91, 0xa9, 0xe4, 0x3e, 0x9c, + 0x8a, 0x16, 0xcb, 0x41, 0x52, 0x8a, 0xd3, 0x36, 0x48, 0xf6, 0x91, 0x0f, 0x10, 0x9c, 0xee, 0x22, + 0x4d, 0x7a, 0xba, 0x02, 0x99, 0x16, 0xa8, 0xc0, 0xc5, 0x6f, 0xa6, 0x74, 0x71, 0x97, 0xb2, 0x10, + 0xde, 0xa9, 0x2d, 0x94, 0x5f, 0x83, 0xd3, 0xb3, 0x96, 0x66, 0xd6, 0xb5, 0x8a, 0x45, 0xdf, 0x69, + 0x38, 0x54, 0x33, 0x14, 0xba, 0xae, 0x39, 0x86, 0xbb, 0xe3, 0x4b, 0xf1, 0x47, 0x08, 0x72, 0xdd, + 0x44, 0x4b, 0x80, 0xdf, 0x82, 0x49, 0x3d, 0xa4, 0x50, 0x5d, 0x41, 0xa2, 0x3a, 0x01, 0x8d, 0xc4, + 0x7b, 0xa2, 0xed, 0xb2, 0x08, 0xd1, 0xcd, 0x32, 0xd3, 0x2e, 0x9d, 0xf7, 0xa1, 0x6c, 0x36, 0xf3, + 0x79, 0x19, 0xc0, 0x2e, 0x82, 0x88, 0x32, 0xae, 0x27, 0x5a, 0x41, 0x56, 0x20, 0x1b, 0xd9, 0x57, + 0x0e, 0x5f, 0x6a, 0x3b, 0xc7, 0xfd, 0xc1, 0x10, 0x9c, 0x4c, 0x94, 0x2b, 0x41, 0x3f, 0x86, 0xb1, + 0x96, 0xad, 0xd1, 0x0b, 0x31, 0x05, 0xe0, 0xcf, 0x49, 0xc0, 0x27, 0x3b, 0x01, 0xb7, 0x84, 0x10, + 0x65, 0x54, 0xdf, 0xaa, 0xda, 0x57, 0xb9, 0xca, 0x9c, 0x55, 0x6a, 0x72, 0x6a, 0xc4, 0x55, 0x0e, + 0xf5, 0xa9, 0x32, 0x49, 0x08, 0x51, 0x46, 0xa3, 0xcf, 0x2d, 0x95, 0x64, 0x11, 0x4e, 0xfb, 0x2f, + 0x81, 0x19, 0x5d, 0xf7, 0xea, 0x9e, 0xa5, 0x71, 0xe6, 0x74, 0xe4, 0x55, 0x5f, 0x67, 0xe5, 0x57, + 0x43, 0x90, 0xeb, 0x26, 0x4e, 0xba, 0xf5, 0x43, 0x04, 0x27, 0xdb, 0x22, 0xaf, 0x56, 0x1d, 0xb6, + 0xce, 0xd7, 0xd4, 0xaa, 0xc5, 0x2a, 0x9a, 0x25, 0xdd, 0x7b, 0x2a, 0x11, 0xeb, 0x1c, 0xd5, 0x05, + 0xdc, 0x2b, 0x3e, 0xdc, 0x8f, 0x3e, 0xcb, 0x5f, 0xa8, 0x9a, 0x7c, 0xcd, 0xab, 0x14, 0x74, 0x56, + 0x97, 0x0d, 0x86, 0xfc, 0x67, 0xda, 0x35, 0x6a, 0x45, 0xbe, 0xd1, 0xa0, 0x6e, 0xc8, 0xe3, 0x2a, + 0x93, 0x6e, 0x2c, 0xab, 0x16, 0x84, 0xce, 0x05, 0xa1, 0x12, 0x7f, 0x07, 0xc1, 0x98, 0xd7, 0xf0, + 0x7b, 0x90, 0x0e, 0x5b, 0x02, 0xbf, 0x5f, 0x4d, 0x79, 0x96, 0x57, 0x84, 0x88, 0x47, 0x8e, 0xa6, + 0xd7, 0xa8, 0xd3, 0x19, 0x92, 0x24, 0xf9, 0x44, 0xc1, 0xc1, 0xe7, 0xb8, 0x35, 0x7e, 0xbd, 0xc9, + 0xf9, 0x35, 0x26, 0xe6, 0x43, 0x29, 0x73, 0xa0, 0x98, 0x0c, 0xf8, 0x66, 0x79, 0x35, 0x04, 0xf9, + 0xae, 0x56, 0xc8, 0x50, 0x3e, 0x47, 0x70, 0x23, 0x31, 0x94, 0xac, 0x21, 0xce, 0x19, 0x55, 0x8d, + 0xf0, 0x56, 0x52, 0xd9, 0xaa, 0x6a, 0x69, 0x2e, 0x57, 0xb9, 0xa3, 0x3d, 0xa1, 0x8e, 0xfb, 0xdf, + 0x0c, 0xf4, 0xe5, 0xad, 0x81, 0x7e, 0x5b, 0x1a, 0x14, 0xdd, 0x92, 0x6f, 0xaf, 0x2e, 0x6a, 0x2e, + 0x7f, 0x14, 0x1a, 0x83, 0x9f, 0xc1, 0x11, 0x19, 0x21, 0x2e, 0x51, 0xee, 0x28, 0xf8, 0x39, 0x19, + 0xfc, 0xf1, 0xb6, 0xe0, 0x87, 0xa2, 0x89, 0x72, 0xd8, 0x8b, 0x93, 0xbb, 0xe4, 0xbb, 0x08, 0x26, + 0xa2, 0x43, 0xa9, 0x88, 0x1e, 0x74, 0xb0, 0x60, 0xef, 0x56, 0x67, 0xf1, 0x31, 0x82, 0xc9, 0xad, + 0x06, 0xc9, 0xb8, 0x9b, 0x70, 0xac, 0xb3, 0x63, 0x0e, 0xcb, 0xe2, 0x17, 0x53, 0xba, 0xab, 0x43, + 0xb6, 0xbc, 0xef, 0x8e, 0x9a, 0x1d, 0x2a, 0x77, 0xaf, 0x31, 0x79, 0x1f, 0xc1, 0x85, 0xd9, 0xf9, + 0x07, 0x0f, 0x44, 0xdb, 0x63, 0x2c, 0x9a, 0x76, 0x6d, 0xde, 0x61, 0xf5, 0xd9, 0x98, 0x91, 0xc1, + 0x4e, 0xe8, 0xf5, 0x87, 0x30, 0x16, 0x47, 0xa0, 0xb6, 0x87, 0x20, 0x1f, 0x2b, 0xef, 0x09, 0x54, + 0x44, 0xc1, 0xfa, 0x16, 0xc9, 0xc4, 0x84, 0x8b, 0xe9, 0x2c, 0x90, 0x6e, 0xbe, 0x01, 0x23, 0xfa, + 0x6a, 0xbd, 0xde, 0xa1, 0x3a, 0xf6, 0x3e, 0x8c, 0xef, 0x12, 0x05, 0xfc, 0xa5, 0x54, 0xf5, 0x00, + 0x4e, 0xfb, 0xcd, 0xff, 0x8a, 0x5d, 0x61, 0xb6, 0x61, 0xda, 0xd5, 0x9d, 0x4d, 0x30, 0xc8, 0x8f, + 0x11, 0xe4, 0xba, 0xc9, 0x93, 0xc6, 0xbe, 0x8f, 0x20, 0x1b, 0x4d, 0x00, 0xd4, 0x75, 0x93, 0xaf, + 0xa9, 0x0d, 0xea, 0x98, 0xcc, 0x50, 0x2d, 0xa6, 0xd7, 0x64, 0x76, 0xdc, 0x49, 0x99, 0x1d, 0xa1, + 0x78, 0xff, 0x3d, 0xb4, 0x2c, 0xa4, 0x2c, 0x32, 0xbd, 0x26, 0x93, 0x64, 0x22, 0x52, 0xd3, 0xbe, + 0x4d, 0xb2, 0x30, 0xb9, 0x40, 0xf9, 0x23, 0xc6, 0x35, 0x2b, 0x7a, 0x56, 0x85, 0x6d, 0xe8, 0xf7, + 0x11, 0x9c, 0x48, 0xd8, 0x94, 0xc6, 0x73, 0x38, 0xc2, 0xfd, 0x1d, 0xb5, 0xf3, 0x19, 0xd7, 0xe3, + 0xca, 0x7d, 0x43, 0x96, 0xa6, 0xa9, 0x14, 0xa5, 0x29, 0xa8, 0x4b, 0x87, 0x79, 0x9b, 0x76, 0xb2, + 0x89, 0x20, 0xb7, 0xe4, 0xd5, 0x97, 0xe8, 0x53, 0x5e, 0xb6, 0x4d, 0x6e, 0x6a, 0x96, 0xf9, 0x4d, + 0x2a, 0x5a, 0x83, 0xc1, 0xce, 0xfe, 0x5d, 0x38, 0x1c, 0x36, 0x43, 0xaa, 0x41, 0x6d, 0x56, 0x97, + 0xcd, 0xd2, 0x89, 0xcd, 0x66, 0xfe, 0x78, 0x7b, 0xb3, 0x14, 0xec, 0x13, 0x65, 0x44, 0xb6, 0x4c, + 0x73, 0xfe, 0x12, 0x57, 0x20, 0x6b, 0x7b, 0x75, 0xd5, 0xa6, 0x4f, 0xb9, 0x6a, 0xb6, 0x2c, 0x12, + 0x8f, 0x7a, 0x57, 0xbc, 0xd6, 0xf7, 0x95, 0xce, 0x6d, 0x36, 0xf3, 0x67, 0x03, 0x61, 0xdd, 0x69, + 0x89, 0x32, 0x61, 0x27, 0x03, 0x13, 0x9d, 0x4b, 0x57, 0xd0, 0xff, 0xef, 0x5c, 0x7e, 0x89, 0xe0, + 0x4c, 0xd4, 0x60, 0xac, 0xd8, 0x06, 0x75, 0xac, 0x0d, 0xd3, 0xae, 0xce, 0xb8, 0x2e, 0xe5, 0x03, + 0x5f, 0xff, 0xff, 0xb3, 0xc6, 0xff, 0x15, 0x82, 0xb3, 0x3d, 0xac, 0x8f, 0xda, 0xa5, 0x61, 0x91, + 0x76, 0x6f, 0xc8, 0x01, 0x50, 0x8f, 0x43, 0x56, 0x94, 0x87, 0xec, 0x7c, 0xca, 0x43, 0xa6, 0x48, + 0xc9, 0x91, 0x8e, 0x4b, 0xf2, 0xce, 0xd8, 0x7d, 0x1d, 0x97, 0x2e, 0xff, 0xe3, 0x14, 0xec, 0x7f, + 0xe8, 0xdf, 0x3e, 0xf8, 0x27, 0x08, 0xc4, 0x3c, 0xcd, 0xc5, 0x57, 0x52, 0x57, 0xb8, 0xd6, 0x38, + 0x30, 0x7b, 0xb5, 0x3f, 0xa6, 0xc0, 0x8d, 0xe4, 0xea, 0xb7, 0x7f, 0xf7, 0xe7, 0x1f, 0x0c, 0x15, + 0xf0, 0xc5, 0x62, 0xd2, 0x74, 0xbb, 0x35, 0xdc, 0x8e, 0x26, 0xfb, 0xc2, 0xc0, 0x9f, 0x22, 0x18, + 0x0e, 0x26, 0x6a, 0x38, 0xb5, 0xda, 0xf8, 0x40, 0x2f, 0x7b, 0xad, 0x4f, 0x2e, 0x69, 0xed, 0x35, + 0x61, 0x6d, 0x11, 0x4f, 0xa7, 0xb5, 0x36, 0xb0, 0xf1, 0x63, 0x04, 0x87, 0xda, 0xc6, 0xd8, 0xf8, + 0x56, 0xda, 0x07, 0x59, 0xc2, 0xe0, 0x3e, 0x7b, 0x7b, 0x30, 0x66, 0x89, 0xa1, 0x24, 0x30, 0xdc, + 0xc6, 0x37, 0x53, 0x7b, 0x5c, 0x4a, 0x28, 0xbe, 0x27, 0x6f, 0xd2, 0x67, 0xf8, 0x15, 0x82, 0xe3, + 0x89, 0xd3, 0x04, 0x3c, 0xdb, 0xef, 0xc8, 0x20, 0x61, 0xb2, 0x91, 0x9d, 0xdb, 0x99, 0x10, 0x09, + 0x74, 0x41, 0x00, 0x9d, 0xc1, 0x77, 0x53, 0x02, 0x6d, 0x55, 0xeb, 0xb0, 0x2c, 0xa8, 0x8e, 0xc0, + 0xf4, 0xcf, 0xf8, 0xe4, 0xb3, 0x7d, 0x4e, 0x85, 0xef, 0xf5, 0x6b, 0x6a, 0xe2, 0x24, 0x31, 0x3b, + 0xbf, 0x53, 0x31, 0x12, 0x73, 0x59, 0x60, 0x9e, 0xc5, 0x33, 0x7d, 0x63, 0xb6, 0x29, 0x17, 0x57, + 0x6a, 0x84, 0xec, 0xef, 0x08, 0xc6, 0x93, 0x27, 0x2a, 0x38, 0x6d, 0x7c, 0x7a, 0xce, 0x7a, 0xb2, + 0xf7, 0x76, 0x28, 0x65, 0xc0, 0x30, 0x77, 0x1b, 0xdd, 0xe0, 0x3f, 0x21, 0x18, 0x4d, 0x18, 0xa5, + 0xe0, 0x99, 0x7e, 0xed, 0xdc, 0x32, 0xde, 0xc9, 0x96, 0x76, 0x22, 0x42, 0xe2, 0x9c, 0x15, 0x38, + 0xef, 0xe0, 0x5b, 0x7d, 0xe3, 0x6c, 0x8d, 0x4f, 0xf0, 0x6f, 0x10, 0x8c, 0xc4, 0xff, 0xf3, 0x08, + 0xdf, 0xec, 0xf3, 0x31, 0x1b, 0xfb, 0x1f, 0xac, 0xec, 0xad, 0x81, 0x78, 0x25, 0x9c, 0x3b, 0x02, + 0xce, 0x75, 0x7c, 0xad, 0xcf, 0x32, 0xa4, 0x56, 0x36, 0x54, 0xd3, 0xc0, 0x7f, 0x41, 0x30, 0x9e, + 0x3c, 0xa3, 0x49, 0x9d, 0x9d, 0x3d, 0x27, 0x46, 0xa9, 0xb3, 0xb3, 0xf7, 0xa0, 0x88, 0xcc, 0x08, + 0x98, 0xb7, 0xf0, 0x8d, 0x3e, 0xee, 0x37, 0x55, 0xf3, 0xe5, 0x45, 0x79, 0xf9, 0x7b, 0x04, 0x47, + 0x3b, 0xbb, 0x58, 0xfc, 0xe6, 0x60, 0x2d, 0x6a, 0x04, 0xef, 0xee, 0xc0, 0xfc, 0x12, 0xd8, 0x5b, + 0x02, 0xd8, 0x4d, 0xfc, 0xa5, 0x94, 0xc0, 0xb6, 0xf4, 0xda, 0xf8, 0xaf, 0x08, 0x26, 0xba, 0x0c, + 0x67, 0x52, 0x97, 0xd5, 0xde, 0x23, 0xa6, 0xd4, 0x65, 0x75, 0x9b, 0x19, 0x51, 0xdf, 0x77, 0xa6, + 0xb8, 0x3c, 0x82, 0x28, 0x86, 0xe3, 0x12, 0xfc, 0x8b, 0x21, 0xf8, 0x7c, 0x9a, 0xce, 0x19, 0x2b, + 0x69, 0x8b, 0x45, 0xfa, 0x41, 0x40, 0xf6, 0x9d, 0x5d, 0x95, 0x29, 0xbd, 0x62, 0x0a, 0xaf, 0xe8, + 0x58, 0x4b, 0x5b, 0x91, 0x62, 0x9d, 0xbe, 0x6a, 0x99, 0x76, 0x4d, 0x5d, 0x75, 0x58, 0x5d, 0x8d, + 0x33, 0x15, 0xdf, 0x4b, 0x9a, 0x44, 0x3c, 0xc3, 0xff, 0x42, 0x30, 0x9e, 0xdc, 0xbb, 0xa7, 0x3e, + 0xee, 0x3d, 0x47, 0x09, 0xa9, 0x8f, 0x7b, 0xef, 0x01, 0x02, 0x79, 0x28, 0x5c, 0x72, 0x1f, 0x97, + 0x53, 0xba, 0xc4, 0x73, 0xa9, 0xa3, 0x7a, 0xa1, 0x3c, 0x35, 0xe9, 0xad, 0xf5, 0x29, 0x82, 0x63, + 0x5b, 0x9a, 0x7e, 0x9c, 0xf6, 0xfc, 0x76, 0x9b, 0x25, 0x64, 0xdf, 0x1a, 0x5c, 0xc0, 0x80, 0x87, + 0xa2, 0x4a, 0xb9, 0xda, 0x31, 0xa0, 0x10, 0x4f, 0xab, 0x2e, 0x8d, 0x74, 0xea, 0x1a, 0xd0, 0x7b, + 0xfa, 0x90, 0xba, 0x06, 0x6c, 0xd3, 0xcf, 0xf7, 0xfd, 0xb4, 0xea, 0x3e, 0x58, 0xc0, 0xff, 0x46, + 0x70, 0xa2, 0x6b, 0x87, 0x89, 0x17, 0xfa, 0x28, 0x5a, 0xbd, 0x3a, 0xec, 0xec, 0x97, 0x77, 0x2e, + 0x48, 0x62, 0xbf, 0x2f, 0xb0, 0xdf, 0xc3, 0xb3, 0xfd, 0xd4, 0x3f, 0xf1, 0x78, 0x56, 0xbd, 0x48, + 0xa6, 0xaa, 0x09, 0xa1, 0xa5, 0xb5, 0xe7, 0x2f, 0x72, 0xe8, 0x93, 0x17, 0x39, 0xf4, 0xc7, 0x17, + 0x39, 0xf4, 0xe1, 0xcb, 0xdc, 0x9e, 0x4f, 0x5e, 0xe6, 0xf6, 0xfc, 0xe1, 0x65, 0x6e, 0xcf, 0xd7, + 0x97, 0x62, 0xcd, 0xab, 0x54, 0x34, 0x6d, 0x69, 0x15, 0x37, 0xd2, 0xfa, 0xe4, 0xd2, 0x8d, 0xe2, + 0xd3, 0x6e, 0x7f, 0xff, 0xa4, 0x5b, 0x26, 0xb5, 0x79, 0xf0, 0x97, 0x60, 0xc1, 0x5f, 0x8a, 0x0c, + 0x8b, 0x7f, 0xae, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x17, 0x63, 0x3c, 0x54, 0x0f, 0x27, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1857,6 +1979,8 @@ type QueryClient interface { // NumNextInitializedTicks returns the provided number of next initialized // ticks in the direction of swapping the token in denom. NumNextInitializedTicks(ctx context.Context, in *NumNextInitializedTicksRequest, opts ...grpc.CallOption) (*NumNextInitializedTicksResponse, error) + // TickRangeUnderlyingAssets returns uderlying asset of a tick range + TickRangeUnderlyingAssets(ctx context.Context, in *TickRangeUnderlyingAssetsRequest, opts ...grpc.CallOption) (*TickRangeUnderlyingAssetsResponse, error) } type queryClient struct { @@ -2002,6 +2126,15 @@ func (c *queryClient) NumNextInitializedTicks(ctx context.Context, in *NumNextIn return out, nil } +func (c *queryClient) TickRangeUnderlyingAssets(ctx context.Context, in *TickRangeUnderlyingAssetsRequest, opts ...grpc.CallOption) (*TickRangeUnderlyingAssetsResponse, error) { + out := new(TickRangeUnderlyingAssetsResponse) + err := c.cc.Invoke(ctx, "/osmosis.concentratedliquidity.v1beta1.Query/TickRangeUnderlyingAssets", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Pools returns all concentrated liquidity pools @@ -2044,6 +2177,8 @@ type QueryServer interface { // NumNextInitializedTicks returns the provided number of next initialized // ticks in the direction of swapping the token in denom. NumNextInitializedTicks(context.Context, *NumNextInitializedTicksRequest) (*NumNextInitializedTicksResponse, error) + // TickRangeUnderlyingAssets returns uderlying asset of a tick range + TickRangeUnderlyingAssets(context.Context, *TickRangeUnderlyingAssetsRequest) (*TickRangeUnderlyingAssetsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -2095,6 +2230,9 @@ func (*UnimplementedQueryServer) GetTotalLiquidity(ctx context.Context, req *Get func (*UnimplementedQueryServer) NumNextInitializedTicks(ctx context.Context, req *NumNextInitializedTicksRequest) (*NumNextInitializedTicksResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method NumNextInitializedTicks not implemented") } +func (*UnimplementedQueryServer) TickRangeUnderlyingAssets(ctx context.Context, req *TickRangeUnderlyingAssetsRequest) (*TickRangeUnderlyingAssetsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TickRangeUnderlyingAssets not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -2370,6 +2508,24 @@ func _Query_NumNextInitializedTicks_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _Query_TickRangeUnderlyingAssets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TickRangeUnderlyingAssetsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TickRangeUnderlyingAssets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.concentratedliquidity.v1beta1.Query/TickRangeUnderlyingAssets", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TickRangeUnderlyingAssets(ctx, req.(*TickRangeUnderlyingAssetsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "osmosis.concentratedliquidity.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -2434,6 +2590,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "NumNextInitializedTicks", Handler: _Query_NumNextInitializedTicks_Handler, }, + { + MethodName: "TickRangeUnderlyingAssets", + Handler: _Query_TickRangeUnderlyingAssets_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "osmosis/concentrated-liquidity/query.proto", @@ -3670,6 +3830,87 @@ func (m *NumNextInitializedTicksResponse) MarshalToSizedBuffer(dAtA []byte) (int return len(dAtA) - i, nil } +func (m *TickRangeUnderlyingAssetsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TickRangeUnderlyingAssetsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TickRangeUnderlyingAssetsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UpperTick != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.UpperTick)) + i-- + dAtA[i] = 0x18 + } + if m.LowerTick != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.LowerTick)) + i-- + dAtA[i] = 0x10 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TickRangeUnderlyingAssetsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TickRangeUnderlyingAssetsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TickRangeUnderlyingAssetsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Token1.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Token0.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -4180,6 +4421,37 @@ func (m *NumNextInitializedTicksResponse) Size() (n int) { return n } +func (m *TickRangeUnderlyingAssetsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + if m.LowerTick != 0 { + n += 1 + sovQuery(uint64(m.LowerTick)) + } + if m.UpperTick != 0 { + n += 1 + sovQuery(uint64(m.UpperTick)) + } + return n +} + +func (m *TickRangeUnderlyingAssetsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Token0.Size() + n += 1 + l + sovQuery(uint64(l)) + l = m.Token1.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -7281,6 +7553,229 @@ func (m *NumNextInitializedTicksResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *TickRangeUnderlyingAssetsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TickRangeUnderlyingAssetsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TickRangeUnderlyingAssetsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LowerTick", wireType) + } + m.LowerTick = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LowerTick |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpperTick", wireType) + } + m.UpperTick = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UpperTick |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TickRangeUnderlyingAssetsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TickRangeUnderlyingAssetsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TickRangeUnderlyingAssetsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token0", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Token0.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token1", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Token1.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/concentrated-liquidity/client/queryproto/query.pb.gw.go b/x/concentrated-liquidity/client/queryproto/query.pb.gw.go index 312473b1cd0..6783df62ec0 100644 --- a/x/concentrated-liquidity/client/queryproto/query.pb.gw.go +++ b/x/concentrated-liquidity/client/queryproto/query.pb.gw.go @@ -609,6 +609,42 @@ func local_request_Query_NumNextInitializedTicks_0(ctx context.Context, marshale } +var ( + filter_Query_TickRangeUnderlyingAssets_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_TickRangeUnderlyingAssets_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TickRangeUnderlyingAssetsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TickRangeUnderlyingAssets_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TickRangeUnderlyingAssets(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TickRangeUnderlyingAssets_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TickRangeUnderlyingAssetsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TickRangeUnderlyingAssets_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TickRangeUnderlyingAssets(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -960,6 +996,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_TickRangeUnderlyingAssets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TickRangeUnderlyingAssets_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TickRangeUnderlyingAssets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1301,6 +1360,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_TickRangeUnderlyingAssets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TickRangeUnderlyingAssets_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TickRangeUnderlyingAssets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1334,6 +1413,8 @@ var ( pattern_Query_GetTotalLiquidity_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "concentratedliquidity", "v1beta1", "get_total_liquidity"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_NumNextInitializedTicks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "concentratedliquidity", "v1beta1", "num_next_initialized_ticks"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_TickRangeUnderlyingAssets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "concentratedliquidity", "v1beta1", "tick_range_underlying_assets"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -1366,4 +1447,6 @@ var ( forward_Query_GetTotalLiquidity_0 = runtime.ForwardResponseMessage forward_Query_NumNextInitializedTicks_0 = runtime.ForwardResponseMessage + + forward_Query_TickRangeUnderlyingAssets_0 = runtime.ForwardResponseMessage ) diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index 9291c350430..bb35d6cb072 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -8,6 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" db "github.com/tendermint/tm-db" + cosmossdk_io_math "cosmossdk.io/math" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/client/queryproto" @@ -336,3 +338,63 @@ func (k Keeper) GetNumNextInitializedTicks(ctx sdk.Context, poolId, numberOfNext return liquidityDepths, nil } + +// GetNumNextInitializedTicks is a method that returns underlying assets of a tick range +func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerTick, upperTick int64) (queryproto.TickRangeUnderlyingAssetsResponse, error) { + pool, err := k.getPoolById(ctx, poolId) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + // Check if the provided tick range is valid according to the pool's tick spacing and module parameters. + if err := validateTickRangeIsValid(pool.GetTickSpacing(), lowerTick, upperTick); err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + // Check lowerTick and upperTick is valid + _, err = k.getTickByTickIndex(ctx, poolId, lowerTick) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("lower tick (%d) not found, error: %w", lowerTick, err) + } + + _, err = k.getTickByTickIndex(ctx, poolId, upperTick) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("upper tick (%d) not found, error: %w", upperTick, err) + } + + // Calculate liquidity of tick range + store := ctx.KVStore(k.storeKey) + prefixBz := types.KeyTickPrefixByPoolId(poolId) + prefixStore := prefix.NewStore(store, prefixBz) + + startTickKey := types.TickIndexToBytes(lowerTick) + boundTickKey := types.TickIndexToBytes(upperTick) + + totalLiquidity := cosmossdk_io_math.LegacyZeroDec() + + iterator := prefixStore.Iterator(startTickKey, storetypes.InclusiveEndBytes(boundTickKey)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + _, err := types.TickIndexFromBytes(iterator.Key()) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + tickStruct, err := ParseTickFromBz(iterator.Value()) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + totalLiquidity = totalLiquidity.Add(tickStruct.LiquidityNet) + } + + actualAmountDenom0, actualAmountDenom1, err := pool.CalcActualAmounts(ctx, lowerTick, upperTick, totalLiquidity) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + return queryproto.TickRangeUnderlyingAssetsResponse{ + Token0: sdk.NewCoin(pool.GetToken0(), actualAmountDenom0.TruncateInt()), + Token1: sdk.NewCoin(pool.GetToken1(), actualAmountDenom1.TruncateInt()), + }, nil +} From 1c1fad3e31ccc00183679949fbb62502f52e9a29 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:38:52 +0700 Subject: [PATCH 02/13] update function --- x/concentrated-liquidity/query.go | 52 ++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index bb35d6cb072..ea3ccb2b754 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -8,8 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" db "github.com/tendermint/tm-db" - cosmossdk_io_math "cosmossdk.io/math" - "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/client/queryproto" @@ -362,30 +360,56 @@ func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerT return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("upper tick (%d) not found, error: %w", upperTick, err) } - // Calculate liquidity of tick range - store := ctx.KVStore(k.storeKey) - prefixBz := types.KeyTickPrefixByPoolId(poolId) - prefixStore := prefix.NewStore(store, prefixBz) + //--------- Calculate liquidity of tick range ----------- - startTickKey := types.TickIndexToBytes(lowerTick) - boundTickKey := types.TickIndexToBytes(upperTick) + // Find first tick initialized + // use false for zeroForOne since we're going from lower tick -> upper tick + zeroForOne := false + swapStrategy := swapstrategy.New(zeroForOne, osmomath.ZeroBigDec(), k.storeKey, osmomath.ZeroDec()) - totalLiquidity := cosmossdk_io_math.LegacyZeroDec() + nextTickIter := swapStrategy.InitializeNextTickIterator(ctx, poolId, types.MinCurrentTick) + defer nextTickIter.Close() - iterator := prefixStore.Iterator(startTickKey, storetypes.InclusiveEndBytes(boundTickKey)) - defer iterator.Close() + if !nextTickIter.Valid() { + return queryproto.TickRangeUnderlyingAssetsResponse{}, types.RanOutOfTicksForPoolError{PoolId: poolId} + } - for ; iterator.Valid(); iterator.Next() { - _, err := types.TickIndexFromBytes(iterator.Key()) + nextTick, err := types.TickIndexFromBytes(nextTickIter.Key()) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + tick, err := k.getTickByTickIndex(ctx, poolId, nextTick) + if err != nil { + return queryproto.TickRangeUnderlyingAssetsResponse{}, err + } + + // use the smallest tick initialized as the starting point for calculating liquidity. + totalLiquidity := tick.LiquidityNet + previousTickIndex := nextTick + nextTickIter.Next() + + // Loop from first tick unit to unit that input range represent + for ; nextTickIter.Valid(); nextTickIter.Next() { + tickIndex, err := types.TickIndexFromBytes(nextTickIter.Key()) if err != nil { return queryproto.TickRangeUnderlyingAssetsResponse{}, err } - tickStruct, err := ParseTickFromBz(iterator.Value()) + tickStruct, err := ParseTickFromBz(nextTickIter.Value()) if err != nil { return queryproto.TickRangeUnderlyingAssetsResponse{}, err } + + if previousTickIndex == lowerTick && tickIndex == upperTick { + break + } + if previousTickIndex == lowerTick && tickIndex != upperTick { + return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("Can not get liquidity of range [%d, %d]", lowerTick, upperTick) + } totalLiquidity = totalLiquidity.Add(tickStruct.LiquidityNet) + previousTickIndex = tickIndex + } actualAmountDenom0, actualAmountDenom1, err := pool.CalcActualAmounts(ctx, lowerTick, upperTick, totalLiquidity) From e77d169eb15c2e298980b7886630bcb0241ad8af Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:39:17 +0700 Subject: [PATCH 03/13] comment --- x/concentrated-liquidity/query.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index ea3ccb2b754..5ea165deaa6 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -338,6 +338,11 @@ func (k Keeper) GetNumNextInitializedTicks(ctx sdk.Context, poolId, numberOfNext } // GetNumNextInitializedTicks is a method that returns underlying assets of a tick range +// Errors: +// * ticks given not found +// * There exists at least 1 tick inside the given range +// TODO: Currently, we can only get the assets of 2 consecutive ticks +// need to think of a way to get assets between any 2 ticks func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerTick, upperTick int64) (queryproto.TickRangeUnderlyingAssetsResponse, error) { pool, err := k.getPoolById(ctx, poolId) if err != nil { From 59ffd56391c103d6cd145989dc8601b769ec3f39 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:39:36 +0700 Subject: [PATCH 04/13] set up test --- x/concentrated-liquidity/query_test.go | 153 +++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/x/concentrated-liquidity/query_test.go b/x/concentrated-liquidity/query_test.go index f07e1d70df1..df77c1a9f15 100644 --- a/x/concentrated-liquidity/query_test.go +++ b/x/concentrated-liquidity/query_test.go @@ -1,9 +1,12 @@ package concentrated_liquidity_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/client/queryproto" "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/math" + "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/types" "github.com/osmosis-labs/osmosis/v19/x/concentrated-liquidity/types/genesis" ) @@ -871,3 +874,153 @@ func (s *KeeperTestSuite) TestGetNumNextInitializedTicks() { }) } } + +func (s *KeeperTestSuite) TestGetTickRangeUnderlyingAssets() { + // Init suite + s.SetupTest() + + // Fund Account + fundCoins := sdk.NewCoins(sdk.NewCoin("atom", osmomath.NewInt(1000000000000000000)), sdk.NewCoin("uosmo", osmomath.NewInt(1000000000000000000))) + s.FundAcc(s.TestAccs[0], fundCoins) + + // Create a default CL pool + s.PrepareCustomConcentratedPool(s.TestAccs[0], "atom", "uosmo", DefaultTickSpacing, osmomath.ZeroDec()) + + // Create a full-range position + data0, err := s.App.ConcentratedLiquidityKeeper.CreatePosition( + s.Ctx, + 1, + s.TestAccs[0], + sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1000000)), sdk.NewCoin("atom", sdk.NewInt(1000000))), + sdk.ZeroInt(), + sdk.ZeroInt(), + types.MinInitializedTick, + 100, + ) + s.Require().NoError(err) + + // Create position at range [-100, 100] + data1, err := s.App.ConcentratedLiquidityKeeper.CreatePosition( + s.Ctx, + 1, + s.TestAccs[0], + sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1000000)), sdk.NewCoin("atom", sdk.NewInt(1000000))), + sdk.ZeroInt(), + sdk.ZeroInt(), + -100, + 100, + ) + s.Require().NoError(err) + + // Create position at range [100, MAX] + data2, err := s.App.ConcentratedLiquidityKeeper.CreatePosition( + s.Ctx, + 1, + s.TestAccs[0], + sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(1000000)), sdk.NewCoin("atom", sdk.NewInt(1000000))), + sdk.ZeroInt(), + sdk.ZeroInt(), + 100, + types.MaxTick, + ) + s.Require().NoError(err) + + clPool, err := s.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(s.Ctx, 1) + + minTickSqrtPrice, _ := math.TickToSqrtPrice(types.MinInitializedTick) + negative100TickSqrtPrice, _ := math.TickToSqrtPrice(-100) + positive100TickSqrtPrice, _ := math.TickToSqrtPrice(100) + maxTickSqrtPrice, _ := math.TickToSqrtPrice(types.MaxTick) + + // For now we have range of tick [Min, -100, 100, Max] + tests := []struct { + name string + req queryproto.TickRangeUnderlyingAssetsRequest + expectedAmount0 sdk.Int + expectedAmount1 sdk.Int + expectedError bool + }{ + { + name: "Pool not found", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 2, + LowerTick: -100, + UpperTick: 100, + }, + expectedError: true, + }, + { + name: "Tick not found", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: 0, + UpperTick: 100, + }, + expectedError: true, + }, + { + name: "Wrong tick spacing", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: 1, + UpperTick: 2, + }, + expectedError: true, + }, + { + name: "Query long range", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: types.MinInitializedTick, + UpperTick: types.MaxTick, + }, + expectedError: true, + }, + { + name: "Query first range", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: types.MinInitializedTick, + UpperTick: -100, + }, + expectedAmount0: sdk.ZeroInt(), + expectedAmount1: math.CalcAmount1Delta(osmomath.BigDecFromDec(data0.Liquidity), minTickSqrtPrice, negative100TickSqrtPrice, true).Dec().TruncateInt(), + expectedError: false, + }, + { + name: "Query second range", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: -100, + UpperTick: 100, + }, + expectedAmount0: math.CalcAmount0Delta(osmomath.BigDecFromDec(data0.Liquidity.Add(data1.Liquidity)), clPool.GetCurrentSqrtPrice(), positive100TickSqrtPrice, true).Dec().TruncateInt(), + expectedAmount1: math.CalcAmount1Delta(osmomath.BigDecFromDec(data0.Liquidity.Add(data1.Liquidity)), clPool.GetCurrentSqrtPrice(), negative100TickSqrtPrice, true).Dec().TruncateInt(), + expectedError: false, + }, + { + name: "Query last range", + req: queryproto.TickRangeUnderlyingAssetsRequest{ + PoolId: 1, + LowerTick: 100, + UpperTick: types.MaxTick, + }, + expectedAmount0: math.CalcAmount0Delta(osmomath.BigDecFromDec(data2.Liquidity), positive100TickSqrtPrice, maxTickSqrtPrice, true).Dec().TruncateInt(), + expectedAmount1: sdk.ZeroInt(), + expectedError: false, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + res, err := s.App.ConcentratedLiquidityKeeper.TickRangeUnderlyingAssets(s.Ctx, test.req.PoolId, test.req.LowerTick, test.req.UpperTick) + if test.expectedError { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(test.expectedAmount0, res.Token0.Amount) + s.Require().Equal(test.expectedAmount1, res.Token1.Amount) + } + }) + } +} From b90d07058981356d5c182a90594d2199f6e547c5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 29 Sep 2023 08:44:17 +0000 Subject: [PATCH 05/13] Generated protofile changes --- x/concentrated-liquidity/client/grpc/grpc_query.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/x/concentrated-liquidity/client/grpc/grpc_query.go b/x/concentrated-liquidity/client/grpc/grpc_query.go index fbafec955c9..0b3fd0fc4b5 100644 --- a/x/concentrated-liquidity/client/grpc/grpc_query.go +++ b/x/concentrated-liquidity/client/grpc/grpc_query.go @@ -170,13 +170,3 @@ func (q Querier) CFMMPoolIdLinkFromConcentratedPoolId(grpcCtx context.Context, return q.Q.CFMMPoolIdLinkFromConcentratedPoolId(ctx, *req) } -func (q Querier) TickRangeUnderlyingAssets(grpcCtx context.Context, - req *queryproto.TickRangeUnderlyingAssetsRequest, -) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "empty request") - } - ctx := sdk.UnwrapSDKContext(grpcCtx) - return q.Q.TickRangeUnderlyingAssets(ctx, *req) -} - From a9f77cac9735f62ebc34050523de0939fe1529bc Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 2 Oct 2023 11:57:03 +0300 Subject: [PATCH 06/13] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa9084492b8..82568cb8d4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [#6468](https://github.com/osmosis-labs/osmosis/pull/6468) feat: remove osmo multihop discount * [#6420](https://github.com/osmosis-labs/osmosis/pull/6420) feat[CL]: Creates a governance set whitelist of addresses that can bypass the normal pool creation restrictions on concentrated liquidity pools +* [#6595](https://github.com/osmosis-labs/osmosis/pull/6595) feat[CL]: Creates a query to get underlying assets of a tick range ### State Breaking From 81c2b89621f4f757ba7e540b3b48db78cc4a9ba7 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:01:45 +0300 Subject: [PATCH 07/13] msgServer --- x/concentrated-liquidity/client/grpc/grpc_query.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/x/concentrated-liquidity/client/grpc/grpc_query.go b/x/concentrated-liquidity/client/grpc/grpc_query.go index ee3c0e66361..a84b20a7eba 100644 --- a/x/concentrated-liquidity/client/grpc/grpc_query.go +++ b/x/concentrated-liquidity/client/grpc/grpc_query.go @@ -171,3 +171,13 @@ func (q Querier) CFMMPoolIdLinkFromConcentratedPoolId(grpcCtx context.Context, return q.Q.CFMMPoolIdLinkFromConcentratedPoolId(ctx, *req) } +func (q Querier) TickRangeUnderlyingAssets(grpcCtx context.Context, + req *queryproto.TickRangeUnderlyingAssetsRequest, +) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.TickRangeUnderlyingAssets(ctx, *req) +} + From 74d2ae0205891a0d36ce837b6be78ab7143b245d Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 2 Oct 2023 09:04:13 +0000 Subject: [PATCH 08/13] Generated protofile changes --- x/concentrated-liquidity/client/grpc/grpc_query.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/x/concentrated-liquidity/client/grpc/grpc_query.go b/x/concentrated-liquidity/client/grpc/grpc_query.go index a84b20a7eba..ee3c0e66361 100644 --- a/x/concentrated-liquidity/client/grpc/grpc_query.go +++ b/x/concentrated-liquidity/client/grpc/grpc_query.go @@ -171,13 +171,3 @@ func (q Querier) CFMMPoolIdLinkFromConcentratedPoolId(grpcCtx context.Context, return q.Q.CFMMPoolIdLinkFromConcentratedPoolId(ctx, *req) } -func (q Querier) TickRangeUnderlyingAssets(grpcCtx context.Context, - req *queryproto.TickRangeUnderlyingAssetsRequest, -) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "empty request") - } - ctx := sdk.UnwrapSDKContext(grpcCtx) - return q.Q.TickRangeUnderlyingAssets(ctx, *req) -} - From fdf746f25fa17b003d0ea0ef2cc4c68225921898 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:15:55 +0300 Subject: [PATCH 09/13] querygen --- proto/osmosis/concentrated-liquidity/query.yml | 5 +++++ x/concentrated-liquidity/client/grpc/grpc_query.go | 10 ++++++++++ x/concentrated-liquidity/client/query_proto_wrap.go | 6 +++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/proto/osmosis/concentrated-liquidity/query.yml b/proto/osmosis/concentrated-liquidity/query.yml index 6dd7e708fe9..9753bac9307 100644 --- a/proto/osmosis/concentrated-liquidity/query.yml +++ b/proto/osmosis/concentrated-liquidity/query.yml @@ -74,3 +74,8 @@ queries: query_func: "k.NumNextInitializedTicks" cli: cmd: "NumNextInitializedTicks" + TickRangeUnderlyingAssets: + proto_wrapper: + query_func: "k.TickRangeUnderlyingAssets" + cli: + cmd: "TickRangeUnderlyingAssets" \ No newline at end of file diff --git a/x/concentrated-liquidity/client/grpc/grpc_query.go b/x/concentrated-liquidity/client/grpc/grpc_query.go index ee3c0e66361..cc6e862c5c6 100644 --- a/x/concentrated-liquidity/client/grpc/grpc_query.go +++ b/x/concentrated-liquidity/client/grpc/grpc_query.go @@ -41,6 +41,16 @@ func (q Querier) UserPositions(grpcCtx context.Context, return q.Q.UserPositions(ctx, *req) } +func (q Querier) TickRangeUnderlyingAssets(grpcCtx context.Context, + req *queryproto.TickRangeUnderlyingAssetsRequest, +) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.TickRangeUnderlyingAssets(ctx, *req) +} + func (q Querier) TickAccumulatorTrackers(grpcCtx context.Context, req *queryproto.TickAccumulatorTrackersRequest, ) (*queryproto.TickAccumulatorTrackersResponse, error) { diff --git a/x/concentrated-liquidity/client/query_proto_wrap.go b/x/concentrated-liquidity/client/query_proto_wrap.go index a7396bfc15b..eb37f525c84 100644 --- a/x/concentrated-liquidity/client/query_proto_wrap.go +++ b/x/concentrated-liquidity/client/query_proto_wrap.go @@ -324,6 +324,10 @@ func (q Querier) TickRangeUnderlyingAssets(ctx sdk.Context, req clquery.TickRang if req.PoolId == 0 { return nil, status.Error(codes.InvalidArgument, "pool id is zero") } + res, err := q.Keeper.TickRangeUnderlyingAssets(ctx, req.PoolId, req.LowerTick, req.UpperTick) + if err != nil { + return nil, err + } - return &clquery.TickRangeUnderlyingAssetsResponse{}, nil + return &clquery.TickRangeUnderlyingAssetsResponse{Token0: res.Token0, Token1: res.Token1}, nil } From 51a6087f3ee96803f3a85fa39b68eba1ba8f1df6 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 2 Oct 2023 12:23:55 +0300 Subject: [PATCH 10/13] lint --- x/concentrated-liquidity/query.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index 5ea165deaa6..93cb19bb851 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -414,7 +414,6 @@ func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerT } totalLiquidity = totalLiquidity.Add(tickStruct.LiquidityNet) previousTickIndex = tickIndex - } actualAmountDenom0, actualAmountDenom1, err := pool.CalcActualAmounts(ctx, lowerTick, upperTick, totalLiquidity) From 1c030e7764cef74e171da4853ac3bd52d197f795 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Mon, 9 Oct 2023 16:51:16 +0700 Subject: [PATCH 11/13] update go doc --- proto/osmosis/concentrated-liquidity/query.proto | 2 +- x/concentrated-liquidity/client/query_proto_wrap.go | 2 +- x/concentrated-liquidity/client/queryproto/query.pb.go | 4 ++-- x/concentrated-liquidity/query.go | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/proto/osmosis/concentrated-liquidity/query.proto b/proto/osmosis/concentrated-liquidity/query.proto index 12df9b3899b..07636c04770 100644 --- a/proto/osmosis/concentrated-liquidity/query.proto +++ b/proto/osmosis/concentrated-liquidity/query.proto @@ -133,7 +133,7 @@ service Query { "num_next_initialized_ticks"; } - // TickRangeUnderlyingAssets returns uderlying asset of a tick range + // TickRangeUnderlyingAssets returns underlying asset of a tick range rpc TickRangeUnderlyingAssets(TickRangeUnderlyingAssetsRequest) returns (TickRangeUnderlyingAssetsResponse) { option (google.api.http).get = "/osmosis/concentratedliquidity/v1beta1/" diff --git a/x/concentrated-liquidity/client/query_proto_wrap.go b/x/concentrated-liquidity/client/query_proto_wrap.go index eb37f525c84..96173ae74a0 100644 --- a/x/concentrated-liquidity/client/query_proto_wrap.go +++ b/x/concentrated-liquidity/client/query_proto_wrap.go @@ -319,7 +319,7 @@ func (q Querier) NumNextInitializedTicks(ctx sdk.Context, req clquery.NumNextIni return &clquery.NumNextInitializedTicksResponse{LiquidityDepths: liquidityDepths, CurrentLiquidity: pool.GetLiquidity(), CurrentTick: pool.GetCurrentTick()}, nil } -// TickRangeUnderlyingAssets returns uderlying asset of a tick range +// TickRangeUnderlyingAssets returns underlying asset of a tick range func (q Querier) TickRangeUnderlyingAssets(ctx sdk.Context, req clquery.TickRangeUnderlyingAssetsRequest) (*clquery.TickRangeUnderlyingAssetsResponse, error) { if req.PoolId == 0 { return nil, status.Error(codes.InvalidArgument, "pool id is zero") diff --git a/x/concentrated-liquidity/client/queryproto/query.pb.go b/x/concentrated-liquidity/client/queryproto/query.pb.go index d9ea3821903..978babe8e4c 100644 --- a/x/concentrated-liquidity/client/queryproto/query.pb.go +++ b/x/concentrated-liquidity/client/queryproto/query.pb.go @@ -1979,7 +1979,7 @@ type QueryClient interface { // NumNextInitializedTicks returns the provided number of next initialized // ticks in the direction of swapping the token in denom. NumNextInitializedTicks(ctx context.Context, in *NumNextInitializedTicksRequest, opts ...grpc.CallOption) (*NumNextInitializedTicksResponse, error) - // TickRangeUnderlyingAssets returns uderlying asset of a tick range + // TickRangeUnderlyingAssets returns underlying asset of a tick range TickRangeUnderlyingAssets(ctx context.Context, in *TickRangeUnderlyingAssetsRequest, opts ...grpc.CallOption) (*TickRangeUnderlyingAssetsResponse, error) } @@ -2177,7 +2177,7 @@ type QueryServer interface { // NumNextInitializedTicks returns the provided number of next initialized // ticks in the direction of swapping the token in denom. NumNextInitializedTicks(context.Context, *NumNextInitializedTicksRequest) (*NumNextInitializedTicksResponse, error) - // TickRangeUnderlyingAssets returns uderlying asset of a tick range + // TickRangeUnderlyingAssets returns underlying asset of a tick range TickRangeUnderlyingAssets(context.Context, *TickRangeUnderlyingAssetsRequest) (*TickRangeUnderlyingAssetsResponse, error) } diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index 93cb19bb851..0ee1c434896 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -337,7 +337,7 @@ func (k Keeper) GetNumNextInitializedTicks(ctx sdk.Context, poolId, numberOfNext return liquidityDepths, nil } -// GetNumNextInitializedTicks is a method that returns underlying assets of a tick range +// TickRangeUnderlyingAssets is a method that returns underlying assets of a tick range // Errors: // * ticks given not found // * There exists at least 1 tick inside the given range @@ -416,6 +416,8 @@ func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerT previousTickIndex = tickIndex } + fmt.Println("liquidity", totalLiquidity) + actualAmountDenom0, actualAmountDenom1, err := pool.CalcActualAmounts(ctx, lowerTick, upperTick, totalLiquidity) if err != nil { return queryproto.TickRangeUnderlyingAssetsResponse{}, err From 7acccbe319c7844fda38f08abfa65108a6200f57 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:59:29 +0700 Subject: [PATCH 12/13] fix return type --- x/concentrated-liquidity/query.go | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/x/concentrated-liquidity/query.go b/x/concentrated-liquidity/query.go index 0ee1c434896..8085504b643 100644 --- a/x/concentrated-liquidity/query.go +++ b/x/concentrated-liquidity/query.go @@ -343,26 +343,26 @@ func (k Keeper) GetNumNextInitializedTicks(ctx sdk.Context, poolId, numberOfNext // * There exists at least 1 tick inside the given range // TODO: Currently, we can only get the assets of 2 consecutive ticks // need to think of a way to get assets between any 2 ticks -func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerTick, upperTick int64) (queryproto.TickRangeUnderlyingAssetsResponse, error) { +func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerTick, upperTick int64) (*queryproto.TickRangeUnderlyingAssetsResponse, error) { pool, err := k.getPoolById(ctx, poolId) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } // Check if the provided tick range is valid according to the pool's tick spacing and module parameters. if err := validateTickRangeIsValid(pool.GetTickSpacing(), lowerTick, upperTick); err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } // Check lowerTick and upperTick is valid _, err = k.getTickByTickIndex(ctx, poolId, lowerTick) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("lower tick (%d) not found, error: %w", lowerTick, err) + return nil, fmt.Errorf("lower tick (%d) not found, error: %w", lowerTick, err) } _, err = k.getTickByTickIndex(ctx, poolId, upperTick) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("upper tick (%d) not found, error: %w", upperTick, err) + return nil, fmt.Errorf("upper tick (%d) not found, error: %w", upperTick, err) } //--------- Calculate liquidity of tick range ----------- @@ -376,17 +376,17 @@ func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerT defer nextTickIter.Close() if !nextTickIter.Valid() { - return queryproto.TickRangeUnderlyingAssetsResponse{}, types.RanOutOfTicksForPoolError{PoolId: poolId} + return nil, types.RanOutOfTicksForPoolError{PoolId: poolId} } nextTick, err := types.TickIndexFromBytes(nextTickIter.Key()) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } tick, err := k.getTickByTickIndex(ctx, poolId, nextTick) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } // use the smallest tick initialized as the starting point for calculating liquidity. @@ -398,32 +398,30 @@ func (k Keeper) TickRangeUnderlyingAssets(ctx sdk.Context, poolId uint64, lowerT for ; nextTickIter.Valid(); nextTickIter.Next() { tickIndex, err := types.TickIndexFromBytes(nextTickIter.Key()) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } tickStruct, err := ParseTickFromBz(nextTickIter.Value()) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } if previousTickIndex == lowerTick && tickIndex == upperTick { break } if previousTickIndex == lowerTick && tickIndex != upperTick { - return queryproto.TickRangeUnderlyingAssetsResponse{}, fmt.Errorf("Can not get liquidity of range [%d, %d]", lowerTick, upperTick) + return nil, fmt.Errorf("Can not get liquidity of range [%d, %d]", lowerTick, upperTick) } totalLiquidity = totalLiquidity.Add(tickStruct.LiquidityNet) previousTickIndex = tickIndex } - fmt.Println("liquidity", totalLiquidity) - actualAmountDenom0, actualAmountDenom1, err := pool.CalcActualAmounts(ctx, lowerTick, upperTick, totalLiquidity) if err != nil { - return queryproto.TickRangeUnderlyingAssetsResponse{}, err + return nil, err } - return queryproto.TickRangeUnderlyingAssetsResponse{ + return &queryproto.TickRangeUnderlyingAssetsResponse{ Token0: sdk.NewCoin(pool.GetToken0(), actualAmountDenom0.TruncateInt()), Token1: sdk.NewCoin(pool.GetToken1(), actualAmountDenom1.TruncateInt()), }, nil From ed8f918ba14f886f53b32b6afb944eb00cb3b0f8 Mon Sep 17 00:00:00 2001 From: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:29:29 +0700 Subject: [PATCH 13/13] remove condition --- x/concentrated-liquidity/client/query_proto_wrap.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/x/concentrated-liquidity/client/query_proto_wrap.go b/x/concentrated-liquidity/client/query_proto_wrap.go index 96173ae74a0..76196d006c5 100644 --- a/x/concentrated-liquidity/client/query_proto_wrap.go +++ b/x/concentrated-liquidity/client/query_proto_wrap.go @@ -321,9 +321,6 @@ func (q Querier) NumNextInitializedTicks(ctx sdk.Context, req clquery.NumNextIni // TickRangeUnderlyingAssets returns underlying asset of a tick range func (q Querier) TickRangeUnderlyingAssets(ctx sdk.Context, req clquery.TickRangeUnderlyingAssetsRequest) (*clquery.TickRangeUnderlyingAssetsResponse, error) { - if req.PoolId == 0 { - return nil, status.Error(codes.InvalidArgument, "pool id is zero") - } res, err := q.Keeper.TickRangeUnderlyingAssets(ctx, req.PoolId, req.LowerTick, req.UpperTick) if err != nil { return nil, err