From 52f189712c4990a69e7f54a03e67e510055e7235 Mon Sep 17 00:00:00 2001 From: "Matt, Park" <45252226+mattverse@users.noreply.github.com> Date: Mon, 24 Oct 2022 22:33:23 -0700 Subject: [PATCH] Add state for Mint: tick and Position (#3136) * WIP: tick * Finish implementing * Update x/concentrated-liquidity/lp.go Co-authored-by: Adam Tucker * Update x/concentrated-liquidity/lp.go Co-authored-by: Adam Tucker * Update x/concentrated-liquidity/lp.go Co-authored-by: Adam Tucker * Change to negative calculations * Add comment * Add getter in osmoutils * Update osmoutils/store_helper.go Co-authored-by: Adam Tucker * Update x/concentrated-liquidity/position.go Co-authored-by: Adam Tucker Co-authored-by: Adam Tucker --- osmoutils/store_helper.go | 13 ++ .../concentratedPool.proto | 9 +- .../concentratedPool.pb.go | 121 +++++++++++++----- x/concentrated-liquidity/lp.go | 28 +++- x/concentrated-liquidity/lp_test.go | 19 ++- x/concentrated-liquidity/position.go | 33 +++-- x/concentrated-liquidity/tick.go | 55 ++++++-- 7 files changed, 214 insertions(+), 64 deletions(-) diff --git a/osmoutils/store_helper.go b/osmoutils/store_helper.go index 86cabae4414..5849febd199 100644 --- a/osmoutils/store_helper.go +++ b/osmoutils/store_helper.go @@ -124,6 +124,19 @@ func MustGet(store store.KVStore, key []byte, result proto.Message) { } } +// GetIfFound gets key from store +// returns a boolean indicating whether value exists for the given key and error +func GetIfFound(store store.KVStore, key []byte, result proto.Message) (found bool, err error) { + b := store.Get(key) + if b == nil { + return false, nil + } + if err := proto.Unmarshal(b, result); err != nil { + return true, err + } + return true, nil +} + // MustSetDec sets dec value to store at key. Panics on any error. func MustSetDec(store store.KVStore, key []byte, value sdk.Dec) { MustSet(store, key, &sdk.DecProto{ diff --git a/proto/osmosis/concentrated-liquidity/concentratedPool.proto b/proto/osmosis/concentrated-liquidity/concentratedPool.proto index 9ae361db297..f280cd15464 100644 --- a/proto/osmosis/concentrated-liquidity/concentratedPool.proto +++ b/proto/osmosis/concentrated-liquidity/concentratedPool.proto @@ -41,9 +41,14 @@ message Pool { } message TickInfo { - string liquidity = 1 [ + string liquidity_gross = 1 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.moretags) = "yaml:\"liquidity\"", + (gogoproto.moretags) = "yaml:\"liquidity_gross\"", + (gogoproto.nullable) = false + ]; + string liquidity_net = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"liquidity_net\"", (gogoproto.nullable) = false ]; } diff --git a/x/concentrated-liquidity/concentratedPool.pb.go b/x/concentrated-liquidity/concentratedPool.pb.go index 1969343f031..e2a3b0be7fe 100644 --- a/x/concentrated-liquidity/concentratedPool.pb.go +++ b/x/concentrated-liquidity/concentratedPool.pb.go @@ -74,7 +74,8 @@ func (m *Pool) XXX_DiscardUnknown() { var xxx_messageInfo_Pool proto.InternalMessageInfo type TickInfo struct { - Liquidity github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=liquidity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity" yaml:"liquidity"` + LiquidityGross github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=liquidity_gross,json=liquidityGross,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity_gross" yaml:"liquidity_gross"` + LiquidityNet github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=liquidity_net,json=liquidityNet,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity_net" yaml:"liquidity_net"` } func (m *TickInfo) Reset() { *m = TickInfo{} } @@ -158,35 +159,39 @@ func init() { } var fileDescriptor_b144264ce94bcf63 = []byte{ - // 441 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x3d, 0x8e, 0xd3, 0x40, - 0x14, 0xb6, 0xb3, 0xd9, 0x2c, 0x3b, 0xa0, 0xd5, 0xee, 0x80, 0x90, 0xd9, 0xc2, 0x5e, 0x59, 0x02, - 0x6d, 0x81, 0x6d, 0x0c, 0xa2, 0x59, 0x51, 0x05, 0x28, 0xd2, 0x45, 0x06, 0x51, 0xd0, 0x04, 0x7b, - 0x3c, 0x24, 0x23, 0x3b, 0x1e, 0x7b, 0x66, 0x12, 0x91, 0x1b, 0x50, 0x52, 0x52, 0xe6, 0x10, 0x9c, - 0x01, 0x45, 0x54, 0x29, 0x11, 0x85, 0x85, 0x92, 0x1b, 0xe4, 0x04, 0xc8, 0xf6, 0xc4, 0x38, 0xc5, - 0x16, 0x29, 0x52, 0xd9, 0xef, 0x7b, 0xef, 0xfb, 0xd1, 0x3c, 0x3d, 0xf0, 0x92, 0xf2, 0x31, 0xe5, - 0x84, 0x3b, 0x88, 0x26, 0x08, 0x27, 0x82, 0xf9, 0x02, 0x87, 0x56, 0x4c, 0xb2, 0x09, 0x09, 0x89, - 0x98, 0xed, 0xc0, 0x7d, 0x4a, 0x63, 0x3b, 0x65, 0x54, 0x50, 0xf8, 0x58, 0xd2, 0xec, 0x66, 0xbf, - 0x66, 0xd9, 0x53, 0x37, 0xc0, 0xc2, 0x77, 0x2f, 0x1f, 0xa1, 0x72, 0x6e, 0x50, 0x92, 0x9c, 0xaa, - 0xa8, 0x14, 0x2e, 0x1f, 0x0c, 0xe9, 0x90, 0x56, 0x78, 0xf1, 0x57, 0xa1, 0xe6, 0xcf, 0x23, 0xd0, - 0x2e, 0x6c, 0xe0, 0x53, 0x70, 0xe2, 0x87, 0x21, 0xc3, 0x9c, 0x6b, 0xea, 0x95, 0x7a, 0x7d, 0xda, - 0x85, 0x9b, 0xdc, 0x38, 0x9b, 0xf9, 0xe3, 0xf8, 0xc6, 0x94, 0x0d, 0xd3, 0xdb, 0x8e, 0xc0, 0x33, - 0xd0, 0x22, 0xa1, 0xd6, 0xba, 0x52, 0xaf, 0xdb, 0x5e, 0x8b, 0x84, 0xf0, 0x13, 0x38, 0xad, 0xc3, - 0x68, 0x47, 0x25, 0xbf, 0xbb, 0xc8, 0x0d, 0xe5, 0x4f, 0x6e, 0x3c, 0x19, 0x12, 0x31, 0x9a, 0x04, - 0x36, 0xa2, 0x63, 0x19, 0x48, 0x7e, 0x2c, 0x1e, 0x46, 0x8e, 0x98, 0xa5, 0x98, 0xdb, 0xbd, 0x44, - 0x6c, 0x72, 0xe3, 0xbc, 0x72, 0xab, 0x85, 0x4c, 0xef, 0xbf, 0x28, 0x7c, 0x08, 0x3a, 0x82, 0x46, - 0x38, 0x79, 0xa6, 0xb5, 0x0b, 0x79, 0x4f, 0x56, 0x35, 0xee, 0x6a, 0xc7, 0x0d, 0xdc, 0x85, 0x19, - 0x80, 0x68, 0xc2, 0x18, 0x4e, 0xc4, 0x80, 0x67, 0x4c, 0x0c, 0x52, 0x46, 0x10, 0xd6, 0x3a, 0x65, - 0xb4, 0xd7, 0x7b, 0x44, 0x7b, 0x83, 0xd1, 0x26, 0x37, 0x2e, 0xaa, 0x68, 0x3c, 0xa5, 0x52, 0xc9, - 0xf4, 0xce, 0xa5, 0xfc, 0xbb, 0x8c, 0x89, 0x7e, 0x01, 0xc1, 0x11, 0xb8, 0xb7, 0xb5, 0x14, 0x04, - 0x45, 0xda, 0x49, 0x69, 0xf6, 0x76, 0xef, 0x77, 0xb8, 0x5f, 0x99, 0x35, 0xb5, 0x4c, 0xef, 0xae, - 0x2c, 0xdf, 0x13, 0x14, 0xdd, 0x5c, 0x7c, 0x9d, 0x1b, 0xca, 0xf7, 0xb9, 0xa1, 0xfc, 0xfa, 0x61, - 0x1d, 0x17, 0xeb, 0xeb, 0x99, 0x31, 0xb8, 0x53, 0xb4, 0x7a, 0xc9, 0x67, 0xba, 0xbb, 0x0d, 0xf5, - 0x00, 0xdb, 0x28, 0xdc, 0xfa, 0x94, 0x13, 0x41, 0x68, 0x72, 0x78, 0xb7, 0xee, 0x87, 0xc5, 0x4a, - 0x57, 0x97, 0x2b, 0x5d, 0xfd, 0xbb, 0xd2, 0xd5, 0x6f, 0x6b, 0x5d, 0x59, 0xae, 0x75, 0xe5, 0xf7, - 0x5a, 0x57, 0x3e, 0xbe, 0x6a, 0x18, 0xc8, 0x0b, 0xb1, 0x62, 0x3f, 0xe0, 0xdb, 0xc2, 0x99, 0xba, - 0xcf, 0x9d, 0x2f, 0xb7, 0xdc, 0x5a, 0xd0, 0x29, 0x6f, 0xe0, 0xc5, 0xbf, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x76, 0xc8, 0x10, 0x58, 0x94, 0x03, 0x00, 0x00, + // 497 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0xb7, 0xdb, 0x34, 0x6d, 0x8e, 0x12, 0xda, 0xa3, 0xaa, 0x4c, 0x07, 0xbb, 0x3a, 0x09, 0xd4, + 0x81, 0xd8, 0x18, 0xc4, 0x52, 0x31, 0x85, 0xbf, 0x59, 0x50, 0x64, 0x10, 0x03, 0x4b, 0x70, 0xce, + 0x47, 0x7a, 0xb2, 0x73, 0x17, 0xdf, 0x5d, 0x2a, 0xf2, 0x0d, 0x18, 0x19, 0x19, 0xfb, 0x21, 0xf8, + 0x0c, 0xa8, 0x62, 0xea, 0x88, 0x18, 0x2c, 0x94, 0x6c, 0x8c, 0xf9, 0x04, 0xc8, 0xf6, 0xc5, 0x4d, + 0x2b, 0x31, 0x64, 0x60, 0xb2, 0xdf, 0xef, 0xbd, 0xf7, 0xfb, 0xfd, 0x74, 0xef, 0x3d, 0xf0, 0x98, + 0xcb, 0x21, 0x97, 0x54, 0x7a, 0x98, 0x33, 0x4c, 0x98, 0x12, 0xa1, 0x22, 0x51, 0x2b, 0xa1, 0xe9, + 0x98, 0x46, 0x54, 0x4d, 0xae, 0xc0, 0x5d, 0xce, 0x13, 0x77, 0x24, 0xb8, 0xe2, 0xf0, 0xae, 0x6e, + 0x73, 0x97, 0xf3, 0x55, 0x97, 0x7b, 0xea, 0xf7, 0x89, 0x0a, 0xfd, 0x83, 0x3b, 0xb8, 0xa8, 0xeb, + 0x15, 0x4d, 0x5e, 0x19, 0x94, 0x0c, 0x07, 0x7b, 0x03, 0x3e, 0xe0, 0x25, 0x9e, 0xff, 0x95, 0x28, + 0xfa, 0xbe, 0x0e, 0x6a, 0xb9, 0x0c, 0xbc, 0x0f, 0x36, 0xc3, 0x28, 0x12, 0x44, 0x4a, 0xcb, 0x3c, + 0x34, 0x8f, 0x1a, 0x6d, 0x38, 0xcf, 0x9c, 0xe6, 0x24, 0x1c, 0x26, 0xc7, 0x48, 0x27, 0x50, 0xb0, + 0x28, 0x81, 0x4d, 0xb0, 0x46, 0x23, 0x6b, 0xed, 0xd0, 0x3c, 0xaa, 0x05, 0x6b, 0x34, 0x82, 0x1f, + 0x40, 0xa3, 0x32, 0x63, 0xad, 0x17, 0xfd, 0xed, 0xf3, 0xcc, 0x31, 0x7e, 0x65, 0xce, 0xbd, 0x01, + 0x55, 0x27, 0xe3, 0xbe, 0x8b, 0xf9, 0x50, 0x1b, 0xd2, 0x9f, 0x96, 0x8c, 0x62, 0x4f, 0x4d, 0x46, + 0x44, 0xba, 0x1d, 0xa6, 0xe6, 0x99, 0xb3, 0x53, 0xaa, 0x55, 0x44, 0x28, 0xb8, 0x24, 0x85, 0xfb, + 0xa0, 0xae, 0x78, 0x4c, 0xd8, 0x03, 0xab, 0x96, 0xd3, 0x07, 0x3a, 0xaa, 0x70, 0xdf, 0xda, 0x58, + 0xc2, 0x7d, 0x98, 0x02, 0x88, 0xc7, 0x42, 0x10, 0xa6, 0x7a, 0x32, 0x15, 0xaa, 0x37, 0x12, 0x14, + 0x13, 0xab, 0x5e, 0x58, 0x7b, 0xba, 0x82, 0xb5, 0x67, 0x04, 0xcf, 0x33, 0x67, 0xb7, 0xb4, 0x26, + 0x47, 0x5c, 0x33, 0xa1, 0x60, 0x47, 0xd3, 0xbf, 0x49, 0x85, 0xea, 0xe6, 0x10, 0x3c, 0x01, 0xdb, + 0x0b, 0x49, 0x45, 0x71, 0x6c, 0x6d, 0x16, 0x62, 0xcf, 0x57, 0x7e, 0x87, 0xdb, 0xa5, 0xd8, 0x32, + 0x17, 0x0a, 0x6e, 0xe8, 0xf0, 0x2d, 0xc5, 0xf1, 0xf1, 0xee, 0xe7, 0x33, 0xc7, 0xf8, 0x7a, 0xe6, + 0x18, 0x3f, 0xbe, 0xb5, 0x36, 0xf2, 0xf1, 0x75, 0xd0, 0x1f, 0x13, 0x6c, 0xe5, 0xb9, 0x0e, 0xfb, + 0xc8, 0x61, 0x0a, 0x6e, 0x55, 0x2f, 0xd7, 0x1b, 0x08, 0x5e, 0x0d, 0xf5, 0xd5, 0xca, 0x66, 0xf6, + 0xaf, 0x0d, 0xa5, 0xa4, 0x43, 0x41, 0xb3, 0x42, 0x5e, 0xe6, 0x00, 0x8c, 0xc1, 0xcd, 0xcb, 0x1a, + 0x46, 0x54, 0xb1, 0x1c, 0x8d, 0xf6, 0x8b, 0x95, 0x05, 0xf7, 0xae, 0x0b, 0x32, 0xa2, 0x50, 0xb0, + 0x5d, 0xc5, 0xaf, 0x89, 0x42, 0x09, 0xd8, 0xea, 0x72, 0x49, 0x15, 0xe5, 0xec, 0xea, 0xea, 0x99, + 0xff, 0x61, 0xf5, 0xda, 0xef, 0xce, 0xa7, 0xb6, 0x79, 0x31, 0xb5, 0xcd, 0xdf, 0x53, 0xdb, 0xfc, + 0x32, 0xb3, 0x8d, 0x8b, 0x99, 0x6d, 0xfc, 0x9c, 0xd9, 0xc6, 0xfb, 0x27, 0x4b, 0x02, 0xfa, 0x40, + 0x5b, 0x49, 0xd8, 0x97, 0x8b, 0xc0, 0x3b, 0xf5, 0x1f, 0x7a, 0x9f, 0xfe, 0x71, 0xea, 0xfd, 0x7a, + 0x71, 0x82, 0x8f, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x11, 0xb1, 0x92, 0xc3, 0x13, 0x04, 0x00, + 0x00, } func (m *Pool) Marshal() (dAtA []byte, err error) { @@ -289,9 +294,19 @@ func (m *TickInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.Liquidity.Size() + size := m.LiquidityNet.Size() i -= size - if _, err := m.Liquidity.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.LiquidityNet.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintConcentratedPool(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size := m.LiquidityGross.Size() + i -= size + if _, err := m.LiquidityGross.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintConcentratedPool(dAtA, i, uint64(size)) @@ -381,7 +396,9 @@ func (m *TickInfo) Size() (n int) { } var l int _ = l - l = m.Liquidity.Size() + l = m.LiquidityGross.Size() + n += 1 + l + sovConcentratedPool(uint64(l)) + l = m.LiquidityNet.Size() n += 1 + l + sovConcentratedPool(uint64(l)) return n } @@ -701,7 +718,7 @@ func (m *TickInfo) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Liquidity", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LiquidityGross", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -729,7 +746,41 @@ func (m *TickInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Liquidity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.LiquidityGross.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LiquidityNet", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConcentratedPool + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthConcentratedPool + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthConcentratedPool + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LiquidityNet.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go index a1bd7e27fdc..de37068922e 100644 --- a/x/concentrated-liquidity/lp.go +++ b/x/concentrated-liquidity/lp.go @@ -24,14 +24,28 @@ func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liqui if liquidityIn.IsZero() { return sdk.Int{}, sdk.Int{}, fmt.Errorf("token in amount is zero") } - // TODO: we need to check if TickInfo is initialized on a specific tick before updating, otherwise get wont work - // k.setTickInfo(ctx, poolId, lowerTick, TickInfo{}) - // k.UpdateTickWithNewLiquidity(ctx, poolId, lowerTick, liquidityIn) - // k.setTickInfo(ctx, poolId, upperTick, TickInfo{}) - // k.UpdateTickWithNewLiquidity(ctx, poolId, upperTick, liquidityIn) - // k.setPosition(ctx, poolId, owner, lowerTick, upperTick, Position{}) - // k.updatePositionWithLiquidity(ctx, poolId, owner, lowerTick, upperTick, liquidityIn) + // update tickInfo state + // TODO: come back to sdk.Int vs sdk.Dec state & truncation + err = k.initOrUpdateTick(ctx, poolId, lowerTick, liquidityIn.TruncateInt(), false) + if err != nil { + return sdk.Int{}, sdk.Int{}, err + } + + // TODO: come back to sdk.Int vs sdk.Dec state & truncation + err = k.initOrUpdateTick(ctx, poolId, upperTick, liquidityIn.TruncateInt(), true) + if err != nil { + return sdk.Int{}, sdk.Int{}, err + } + + // update position state + // TODO: come back to sdk.Int vs sdk.Dec state & truncation + err = k.initOrUpdatePosition(ctx, poolId, owner, lowerTick, upperTick, liquidityIn.TruncateInt()) + if err != nil { + return sdk.Int{}, sdk.Int{}, err + } + + // now calculate amount for token0 and token1 pool := k.getPoolbyId(ctx, poolId) currentSqrtPrice := pool.CurrentSqrtPrice diff --git a/x/concentrated-liquidity/lp_test.go b/x/concentrated-liquidity/lp_test.go index 40938cb3afe..63b7dd64bd7 100644 --- a/x/concentrated-liquidity/lp_test.go +++ b/x/concentrated-liquidity/lp_test.go @@ -31,7 +31,24 @@ func (s *KeeperTestSuite) TestMint() { asset0, asset1, err := s.App.ConcentratedLiquidityKeeper.Mint(s.Ctx, poolId, s.TestAccs[0], liquidity, lowerTick, upperTick) s.Require().NoError(err) - s.Require().Equal(sdk.NewInt(1), asset0) s.Require().Equal(sdk.NewInt(5000), asset1) + + // check position state + // 1517 is from the liquidity originally provided + position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, poolId, s.TestAccs[0], lowerTick, upperTick) + s.Require().NoError(err) + s.Require().Equal(sdk.NewInt(1517), position.Liquidity) + + // check tick state + // 1517 is from the liquidity originally provided + lowerTickInfo, err := s.App.ConcentratedLiquidityKeeper.GetTickInfo(s.Ctx, poolId, lowerTick) + s.Require().NoError(err) + s.Require().Equal(sdk.NewInt(1517), lowerTickInfo.LiquidityGross) + s.Require().Equal(sdk.NewInt(1517), lowerTickInfo.LiquidityNet) + + upperTickInfo, err := s.App.ConcentratedLiquidityKeeper.GetTickInfo(s.Ctx, poolId, upperTick) + s.Require().NoError(err) + s.Require().Equal(sdk.NewInt(1517), upperTickInfo.LiquidityGross) + s.Require().Equal(sdk.NewInt(-1517), upperTickInfo.LiquidityNet) } diff --git a/x/concentrated-liquidity/position.go b/x/concentrated-liquidity/position.go index 1ed4bb5f18e..4c7fe3aea97 100644 --- a/x/concentrated-liquidity/position.go +++ b/x/concentrated-liquidity/position.go @@ -7,31 +7,44 @@ import ( types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types" ) -// nolint: unused -func (k Keeper) updatePositionWithLiquidity(ctx sdk.Context, +func (k Keeper) initOrUpdatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64, liquidityDelta sdk.Int, -) { - position := k.getPosition(ctx, poolId, owner, lowerTick, upperTick) +) (err error) { + position, err := k.GetPosition(ctx, poolId, owner, lowerTick, upperTick) + if err != nil { + return err + } liquidityBefore := position.Liquidity + + // note that liquidityIn can be either positive or negative. + // If negative, this would work as a subtraction from liquidityBefore liquidityAfter := liquidityBefore.Add(liquidityDelta) + position.Liquidity = liquidityAfter k.setPosition(ctx, poolId, owner, lowerTick, upperTick, position) + return nil } -// nolint: unused -func (k Keeper) getPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64) Position { +func (k Keeper) GetPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64) (position Position, err error) { store := ctx.KVStore(k.storeKey) - - var position Position + positionStruct := Position{} key := types.KeyPosition(poolId, owner, lowerTick, upperTick) - osmoutils.MustGet(store, key, &position) - return position + found, err := osmoutils.GetIfFound(store, key, &positionStruct) + // return 0 values if key has not been initialized + if !found { + return Position{Liquidity: sdk.ZeroInt()}, nil + } + if err != nil { + return positionStruct, err + } + + return positionStruct, nil } // nolint: unused diff --git a/x/concentrated-liquidity/tick.go b/x/concentrated-liquidity/tick.go index 5b38be7b4e4..b92e70c0a02 100644 --- a/x/concentrated-liquidity/tick.go +++ b/x/concentrated-liquidity/tick.go @@ -26,14 +26,41 @@ func (k Keeper) tickToSqrtPrice(tickIndex sdk.Int) (sdk.Dec, error) { // return sdk.Int{} // } -func (k Keeper) UpdateTickWithNewLiquidity(ctx sdk.Context, poolId uint64, tickIndex int64, liquidityDelta sdk.Int) { - tickInfo := k.getTickInfo(ctx, poolId, tickIndex) +func (k Keeper) initOrUpdateTick(ctx sdk.Context, poolId uint64, tickIndex int64, liquidityIn sdk.Int, upper bool) (err error) { + tickInfo, err := k.GetTickInfo(ctx, poolId, tickIndex) + if err != nil { + return err + } + + // calculate liquidityGross, which does not care about whether liquidityIn is positive or negative + liquidityBefore := tickInfo.LiquidityGross - liquidityBefore := tickInfo.Liquidity - liquidityAfter := liquidityBefore.Add(liquidityDelta) - tickInfo.Liquidity = liquidityAfter + // note that liquidityIn can be either positive or negative. + // If negative, this would work as a subtraction from liquidityBefore + liquidityAfter := liquidityBefore.Add(liquidityIn) + + tickInfo.LiquidityGross = liquidityAfter + + // calculate liquidityNet, which we take into account and track depending on whether liquidityIn is positive or negative + if upper { + tickInfo.LiquidityNet = tickInfo.LiquidityNet.Sub(liquidityIn) + } else { + tickInfo.LiquidityNet = tickInfo.LiquidityNet.Add(liquidityIn) + } k.setTickInfo(ctx, poolId, tickIndex, tickInfo) + + return nil +} + +// nolint: unused +func (k Keeper) crossTick(ctx sdk.Context, poolId uint64, tickIndex int64) (liquidityDelta sdk.Int, err error) { + tickInfo, err := k.GetTickInfo(ctx, poolId, tickIndex) + if err != nil { + return sdk.Int{}, err + } + + return tickInfo.LiquidityNet, nil } // NextInitializedTick returns the next initialized tick index based on the @@ -87,12 +114,22 @@ func (k Keeper) NextInitializedTick(ctx sdk.Context, poolId uint64, tickIndex in return 0, false } -func (k Keeper) getTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64) TickInfo { +// getTickInfo gets tickInfo given poolId and tickIndex. Returns a boolean field that returns true if value is found for given key. +func (k Keeper) GetTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64) (tickInfo TickInfo, err error) { store := ctx.KVStore(k.storeKey) - tickInfo := TickInfo{} + tickStruct := TickInfo{} key := types.KeyTick(poolId, tickIndex) - osmoutils.MustGet(store, key, &tickInfo) - return tickInfo + + found, err := osmoutils.GetIfFound(store, key, &tickStruct) + // return 0 values if key has not been initialized + if !found { + return TickInfo{LiquidityGross: sdk.ZeroInt(), LiquidityNet: sdk.ZeroInt()}, err + } + if err != nil { + return tickStruct, err + } + + return tickStruct, nil } func (k Keeper) setTickInfo(ctx sdk.Context, poolId uint64, tickIndex int64, tickInfo TickInfo) {