diff --git a/app/apptesting/concentrated_liquidity.go b/app/apptesting/concentrated_liquidity.go index 1b192a067d1..17b010a6fb4 100644 --- a/app/apptesting/concentrated_liquidity.go +++ b/app/apptesting/concentrated_liquidity.go @@ -74,7 +74,7 @@ func (s *KeeperTestHelper) PrepareConcentratedPoolWithCoinsAndLockedFullRangePos s.FundAcc(s.TestAccs[0], fundCoins) positionId, _, _, _, _, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), s.TestAccs[0], fundCoins, time.Hour*24*14) s.Require().NoError(err) - clPool, err = s.App.ConcentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(s.Ctx, clPool.GetId()) + clPool, err = s.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(s.Ctx, clPool.GetId()) s.Require().NoError(err) return clPool, concentratedLockId, positionId } diff --git a/go.mod b/go.mod index 00ddcdb659d..06504731330 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/ory/dockertest/v3 v3.10.0 github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111 - github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae + github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230511015306-615fa4fcbe56 github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304 github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230331072320-5d6f6cfa2627 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 181ec5f621c..493d08f32ac 100644 --- a/go.sum +++ b/go.sum @@ -938,8 +938,8 @@ github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:Ylmch github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI= github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111 h1:1ahWbf9iF9sxDOjxrHWFaBGLE0nWFdpiX1pqObUaJO8= github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111/go.mod h1:a7lhiXRpn8QJ21OhFpaEnUNErTSIafaYpp02q6uI/Dk= -github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae h1:I1Cy+GpTPWbVi0lBw9+bS1w42YfQjvXNK9bW4YbHhcs= -github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230511015306-615fa4fcbe56 h1:27yWLC0uXSatRy8aRn0yinHU+K31bkjBRmNnQUDO0Ks= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230511015306-615fa4fcbe56/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A= github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304 h1:RIrWLzIiZN5Xd2JOfSOtGZaf6V3qEQYg6EaDTAkMnCo= github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304/go.mod h1:yPWoJTj5RKrXKUChAicp+G/4Ni/uVEpp27mi/FF/L9c= github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230331072320-5d6f6cfa2627 h1:A0SwZgp4bmJFbivYJc8mmVhMjrr3EdUZluBYFke11+w= diff --git a/osmoutils/errors.go b/osmoutils/errors.go new file mode 100644 index 00000000000..51dc951915c --- /dev/null +++ b/osmoutils/errors.go @@ -0,0 +1,11 @@ +package osmoutils + +import "fmt" + +type DecNotFoundError struct { + Key string +} + +func (e DecNotFoundError) Error() string { + return fmt.Sprintf("no sdk.Dec at key (%s)", e.Key) +} diff --git a/osmoutils/store_helper.go b/osmoutils/store_helper.go index 232815179fa..80299d1743d 100644 --- a/osmoutils/store_helper.go +++ b/osmoutils/store_helper.go @@ -85,7 +85,7 @@ func GetIterValuesWithStop[T any]( // HasAnyAtPrefix returns true if there is at least one value in the given prefix. func HasAnyAtPrefix[T any](storeObj store.KVStore, prefix []byte, parseValue func([]byte) (T, error)) (bool, error) { - _, err := GetFirstValueInRange(storeObj, prefix, sdk.PrefixEndBytes(prefix),false, parseValue) + _, err := GetFirstValueInRange(storeObj, prefix, sdk.PrefixEndBytes(prefix), false, parseValue) if err != nil { if err == ErrNoValuesInRange { return false, nil @@ -180,6 +180,21 @@ func MustGetDec(store store.KVStore, key []byte) sdk.Dec { return result.Dec } +// GetDec gets dec value from store at key. Returns error if: +// - database error occurs. +// - no value at given key is found. +func GetDec(store store.KVStore, key []byte) (sdk.Dec, error) { + result := &sdk.DecProto{} + isFound, err := Get(store, key, result) + if err != nil { + return sdk.Dec{}, err + } + if !isFound { + return sdk.Dec{}, DecNotFoundError{Key: string(key)} + } + return result.Dec, nil +} + // Get returns a value at key by mutating the result parameter. Returns true if the value was found and the // result mutated correctly. If the value is not in the store, returns false. Returns error only when database or serialization errors occur. (And when an error occurs, returns false) func Get(store store.KVStore, key []byte, result proto.Message) (found bool, err error) { diff --git a/osmoutils/store_helper_test.go b/osmoutils/store_helper_test.go index e153c6cf3cd..21d2a134cf5 100644 --- a/osmoutils/store_helper_test.go +++ b/osmoutils/store_helper_test.go @@ -1243,3 +1243,69 @@ func (s *TestSuite) TestHasAnyAtPrefix() { }) } } + +func (s *TestSuite) TestGetDec() { + tests := map[string]struct { + // keys and values to preset + preSetKeyValues map[string]sdk.Dec + + // keys and values to attempt to get and validate + expectedGetKeyValues map[string]sdk.Dec + + expectError error + }{ + "valid get": { + preSetKeyValues: map[string]sdk.Dec{ + keyA: sdk.OneDec(), + keyB: sdk.OneDec().Add(sdk.OneDec()), + keyC: sdk.OneDec().Add(sdk.OneDec()).Add(sdk.OneDec()), + }, + + expectedGetKeyValues: map[string]sdk.Dec{ + keyA: sdk.OneDec(), + keyB: sdk.OneDec().Add(sdk.OneDec()), + keyC: sdk.OneDec().Add(sdk.OneDec()).Add(sdk.OneDec()), + }, + }, + "error: attempt to get non-existent key": { + preSetKeyValues: map[string]sdk.Dec{ + keyA: sdk.OneDec(), + keyC: sdk.OneDec().Add(sdk.OneDec()).Add(sdk.OneDec()), + }, + + expectedGetKeyValues: map[string]sdk.Dec{ + keyA: sdk.OneDec(), + keyB: {}, // this one errors + }, + + expectError: osmoutils.DecNotFoundError{Key: keyB}, + }, + } + + for name, tc := range tests { + s.Run(name, func() { + s.SetupTest() + // Setup + for key, value := range tc.preSetKeyValues { + osmoutils.MustSetDec(s.store, []byte(key), value) + } + + for key, expectedValue := range tc.expectedGetKeyValues { + // System under test. + actualDec, err := osmoutils.GetDec(s.store, []byte(key)) + + // Assertions. + + if tc.expectError != nil { + s.Require().Error(err) + s.Require().ErrorIs(err, tc.expectError) + return + } + + s.Require().NoError(err) + s.Require().Equal(expectedValue.String(), actualDec.String()) + } + }) + + } +} diff --git a/proto/osmosis/superfluid/tx.proto b/proto/osmosis/superfluid/tx.proto index a30df7a5299..1a4301eb6d4 100644 --- a/proto/osmosis/superfluid/tx.proto +++ b/proto/osmosis/superfluid/tx.proto @@ -204,5 +204,13 @@ message MsgAddToConcentratedLiquiditySuperfluidPositionResponse { (gogoproto.moretags) = "yaml:\"amount1\"", (gogoproto.nullable) = false ]; + // new_liquidity is the final liquidity after the add. + // It includes the liquidity that existed before in the position + // and the new liquidity that was added to the position. + string new_liquidity = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.moretags) = "yaml:\"new_liquidity\"", + (gogoproto.nullable) = false + ]; uint64 lock_id = 4 [ (gogoproto.moretags) = "yaml:\"lock_id\"" ]; } \ No newline at end of file diff --git a/tests/cl-genesis-positions/convert.go b/tests/cl-genesis-positions/convert.go index ea5c3fca813..b4b7698769b 100644 --- a/tests/cl-genesis-positions/convert.go +++ b/tests/cl-genesis-positions/convert.go @@ -115,7 +115,7 @@ func ConvertSubgraphToOsmosisGenesis(positionCreatorAddresses []sdk.AccAddress, fmt.Println("Created pool id of: ", poolId) - pool, err := osmosis.App.ConcentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(osmosis.Ctx, poolId) + pool, err := osmosis.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(osmosis.Ctx, poolId) if err != nil { panic(err) } diff --git a/x/concentrated-liquidity/client/cli/tx.go b/x/concentrated-liquidity/client/cli/tx.go index 35358950de8..3f750d23c33 100644 --- a/x/concentrated-liquidity/client/cli/tx.go +++ b/x/concentrated-liquidity/client/cli/tx.go @@ -49,9 +49,9 @@ func NewCreateConcentratedPoolCmd() (*osmocli.TxCliDesc, *clmodel.MsgCreateConce func NewCreatePositionCmd() (*osmocli.TxCliDesc, *types.MsgCreatePosition) { return &osmocli.TxCliDesc{ - Use: "create-position [pool-id] [lower-tick] [upper-tick] [token-0-amount] [token-1-amount] [token-0-min-amount] [token-1-min-amount]", + Use: "create-position [pool-id] [lower-tick] [upper-tick] [coins] [token-0-min-amount] [token-1-min-amount]", Short: "create or add to existing concentrated liquidity position", - Example: "create-position 1 \"[-69082]\" 69082 1000000000 10000000 0 0 --from val --chain-id osmosis-1", + Example: "create-position 1 \"[-69082]\" 69082 1000000000uosmo,10000000uion 0 0 --from val --chain-id osmosis-1", }, &types.MsgCreatePosition{} } diff --git a/x/concentrated-liquidity/client/query_proto_wrap.go b/x/concentrated-liquidity/client/query_proto_wrap.go index 15608c10d36..7e1a3b1dcb3 100644 --- a/x/concentrated-liquidity/client/query_proto_wrap.go +++ b/x/concentrated-liquidity/client/query_proto_wrap.go @@ -37,7 +37,7 @@ func (q Querier) UserPositions(ctx sdk.Context, req clquery.UserPositionsRequest for _, position := range userPositions { // get the pool from the position - pool, err := q.Keeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, position.PoolId) + pool, err := q.Keeper.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -67,7 +67,7 @@ func (q Querier) PositionById(ctx sdk.Context, req clquery.PositionByIdRequest) return nil, status.Error(codes.Internal, err.Error()) } - positionPool, err := q.Keeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, position.PoolId) + positionPool, err := q.Keeper.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -148,7 +148,7 @@ func (q Querier) LiquidityNetInDirection(ctx sdk.Context, req clquery.LiquidityN return nil, err } - pool, err := q.Keeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, req.PoolId) + pool, err := q.Keeper.GetConcentratedPoolById(ctx, req.PoolId) if err != nil { return nil, err } diff --git a/x/concentrated-liquidity/export_test.go b/x/concentrated-liquidity/export_test.go index af71c67fe51..4ef0a24224a 100644 --- a/x/concentrated-liquidity/export_test.go +++ b/x/concentrated-liquidity/export_test.go @@ -150,8 +150,8 @@ func (k Keeper) UpdateFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64, l return k.updateFullRangeLiquidityInPool(ctx, poolId, liquidity) } -func (k Keeper) MintSharesLockAndUpdate(ctx sdk.Context, concentratedPoolId, positionId uint64, owner sdk.AccAddress, remainingLockDuration time.Duration) (concentratedLockID uint64, underlyingLiquidityTokenized sdk.Coins, err error) { - return k.mintSharesLockAndUpdate(ctx, concentratedPoolId, positionId, owner, remainingLockDuration) +func (k Keeper) MintSharesAndLock(ctx sdk.Context, concentratedPoolId, positionId uint64, owner sdk.AccAddress, remainingLockDuration time.Duration) (concentratedLockID uint64, underlyingLiquidityTokenized sdk.Coins, err error) { + return k.mintSharesAndLock(ctx, concentratedPoolId, positionId, owner, remainingLockDuration) } func (k Keeper) SetPositionIdToLock(ctx sdk.Context, positionId, underlyingLockId uint64) { diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go index 1237f389065..30dbec38026 100644 --- a/x/concentrated-liquidity/lp.go +++ b/x/concentrated-liquidity/lp.go @@ -45,6 +45,7 @@ func (k Keeper) createPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddr if err := validateTickRangeIsValid(pool.GetTickSpacing(), lowerTick, upperTick); err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err } + amount0Desired := tokensProvided.AmountOf(pool.GetToken0()) amount1Desired := tokensProvided.AmountOf(pool.GetToken1()) if amount0Desired.IsZero() && amount1Desired.IsZero() { @@ -299,7 +300,7 @@ func (k Keeper) addToPosition(ctx sdk.Context, owner sdk.AccAddress, positionId // Create new position with updated liquidity. amount0Desired := amount0Withdrawn.Add(amount0Added) amount1Desired := amount1Withdrawn.Add(amount1Added) - pool, err := k.GetPoolFromPoolIdAndConvertToConcentrated(ctx, position.PoolId) + pool, err := k.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, err } diff --git a/x/concentrated-liquidity/pool.go b/x/concentrated-liquidity/pool.go index 2b8de40ad91..64612d40282 100644 --- a/x/concentrated-liquidity/pool.go +++ b/x/concentrated-liquidity/pool.go @@ -225,7 +225,9 @@ func convertPoolInterfaceToConcentrated(poolI poolmanagertypes.PoolI) (types.Con return concentratedPool, nil } -func (k Keeper) GetPoolFromPoolIdAndConvertToConcentrated(ctx sdk.Context, poolId uint64) (types.ConcentratedPoolExtension, error) { +// GetConcentratedPoolById returns a concentrated pool interface associated with the given id. +// Returns error if fails to fetch the pool from the store. +func (k Keeper) GetConcentratedPoolById(ctx sdk.Context, poolId uint64) (types.ConcentratedPoolExtension, error) { poolI, err := k.GetPool(ctx, poolId) if err != nil { return nil, err @@ -271,7 +273,7 @@ func (k Keeper) GetSerializedPools(ctx sdk.Context, pagination *query.PageReques // It returns an error if the tick spacing is not one of the authorized tick spacings or is not less than the current tick spacing of the respective pool. func (k Keeper) DecreaseConcentratedPoolTickSpacing(ctx sdk.Context, poolIdToTickSpacingRecord []types.PoolIdToTickSpacingRecord) error { for _, poolIdToTickSpacingRecord := range poolIdToTickSpacingRecord { - pool, err := k.GetPoolFromPoolIdAndConvertToConcentrated(ctx, poolIdToTickSpacingRecord.PoolId) + pool, err := k.GetConcentratedPoolById(ctx, poolIdToTickSpacingRecord.PoolId) if err != nil { return err } diff --git a/x/concentrated-liquidity/position.go b/x/concentrated-liquidity/position.go index 8639a0e5b55..420d14065d9 100644 --- a/x/concentrated-liquidity/position.go +++ b/x/concentrated-liquidity/position.go @@ -286,13 +286,13 @@ func (k Keeper) deletePosition(ctx sdk.Context, // CreateFullRangePosition creates a full range (min to max tick) concentrated liquidity position for the given pool ID, owner, and coins. // The function returns the amounts of token 0 and token 1, and the liquidity created from the position. -func (k Keeper) CreateFullRangePosition(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, joinTime time.Time, err error) { +func (k Keeper) CreateFullRangePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, coins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, joinTime time.Time, err error) { // Check that exactly two coins are provided. if len(coins) != 2 { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, types.NumCoinsError{NumCoins: len(coins)} } - concentratedPool, err := k.GetPoolFromPoolIdAndConvertToConcentrated(ctx, clPoolId) + concentratedPool, err := k.GetConcentratedPoolById(ctx, poolId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err } @@ -329,7 +329,7 @@ func (k Keeper) CreateFullRangePositionLocked(ctx sdk.Context, clPoolId uint64, // Mint cl shares for the position and lock them for the remaining lock duration. // Also sets the position ID to underlying lock ID mapping. - concentratedLockId, _, err := k.mintSharesLockAndUpdate(ctx, clPoolId, positionId, owner, remainingLockDuration) + concentratedLockId, _, err := k.mintSharesAndLock(ctx, clPoolId, positionId, owner, remainingLockDuration) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, err } @@ -349,7 +349,7 @@ func (k Keeper) CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint6 // Mint cl shares for the position and lock them for the remaining lock duration. // Also sets the position ID to underlying lock ID mapping. - concentratedLockId, underlyingLiquidityTokenized, err := k.mintSharesLockAndUpdate(ctx, clPoolId, positionId, owner, remainingLockDuration) + concentratedLockId, underlyingLiquidityTokenized, err := k.mintSharesAndLock(ctx, clPoolId, positionId, owner, remainingLockDuration) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, err } @@ -363,11 +363,11 @@ func (k Keeper) CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint6 return positionId, amount0, amount1, liquidity, joinTime, concentratedLockID, nil } -// mintSharesLockAndUpdate mints the shares for the full range concentrated liquidity position and locks them for the given duration. It also updates the position ID to underlying lock ID mapping. +// mintSharesAndLock mints the shares for the full range concentrated liquidity position and locks them for the given duration. It also updates the position ID to underlying lock ID mapping. // In the context of concentrated liquidity, shares need to be minted in order for a lock in its current form to be utilized (we cannot lock non-coin objects). // In turn, the locks are a prerequisite for superfluid to be enabled. // Additionally, the cl share gets sent to the lockup module account, which, in order to be sent via bank, must be minted. -func (k Keeper) mintSharesLockAndUpdate(ctx sdk.Context, concentratedPoolId, positionId uint64, owner sdk.AccAddress, remainingLockDuration time.Duration) (concentratedLockID uint64, underlyingLiquidityTokenized sdk.Coins, err error) { +func (k Keeper) mintSharesAndLock(ctx sdk.Context, concentratedPoolId, positionId uint64, owner sdk.AccAddress, remainingLockDuration time.Duration) (concentratedLockID uint64, underlyingLiquidityTokenized sdk.Coins, err error) { // Ensure the provided position is full range. position, err := k.GetPosition(ctx, positionId) if err != nil { @@ -392,7 +392,9 @@ func (k Keeper) mintSharesLockAndUpdate(ctx sdk.Context, concentratedPoolId, pos // Lock the position for the specified duration. // Note, the end blocker for the lockup module contains an exception for this CL denom. When a lock with a denom of cl/pool/{poolId} is mature, - // it does not send the coins to the owner account and instead burns them. This is strictly to use well tested pre-existing methods rather than potentially introducing bugs with new logic and methods. + // it does not send the coins to the owner account but instead burns them. + // This is implemented in such a way to use well-tested pre-existing methods rather than + // completely re-implementing concentrated liquidity superfluid infrastructure that has a risk of introducing bugs with new logic and methods. concentratedLock, err := k.lockupKeeper.CreateLock(ctx, owner, underlyingLiquidityTokenized, remainingLockDuration) if err != nil { return 0, sdk.Coins{}, err @@ -722,12 +724,18 @@ func (k Keeper) positionHasActiveUnderlyingLockAndUpdate(ctx sdk.Context, positi return hasActiveUnderlyingLock, lockId, nil } -// MustGetFullRangeLiquidityInPool returns the total liquidity that is currently in the full range of the pool. -func (k Keeper) MustGetFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64) sdk.Dec { +// GetFullRangeLiquidityInPool returns the total liquidity that is currently in the full range of the pool. +// Returns error if: +// - fails to retrieve data from the store. +// - there is no full range liquidity in the pool. +func (k Keeper) GetFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64) (sdk.Dec, error) { store := ctx.KVStore(k.storeKey) poolIdLiquidityKey := types.KeyPoolIdForLiquidity(poolId) - currentTotalFullRangeLiquidity := osmoutils.MustGetDec(store, poolIdLiquidityKey) - return currentTotalFullRangeLiquidity + currentTotalFullRangeLiquidity, err := osmoutils.GetDec(store, poolIdLiquidityKey) + if err != nil { + return sdk.Dec{}, err + } + return currentTotalFullRangeLiquidity, nil } // updateFullRangeLiquidityInPool updates the total liquidity store that is currently in the full range of the pool. diff --git a/x/concentrated-liquidity/position_test.go b/x/concentrated-liquidity/position_test.go index 524c1a55538..3b1ed50c920 100644 --- a/x/concentrated-liquidity/position_test.go +++ b/x/concentrated-liquidity/position_test.go @@ -1461,9 +1461,11 @@ func (s *KeeperTestSuite) TestCreateFullRangePosition() { } } -func (s *KeeperTestSuite) TestMintSharesLockAndUpdate() { - defaultAddress := s.TestAccs[0] - defaultPositionCoins := sdk.NewCoins(DefaultCoin0, DefaultCoin1) +func (s *KeeperTestSuite) TestMintSharesAndLock() { + var ( + defaultPositionCoins = sdk.NewCoins(DefaultCoin0, DefaultCoin1) + defaultAddress = s.TestAccs[0] + ) tests := []struct { name string @@ -1504,14 +1506,14 @@ func (s *KeeperTestSuite) TestMintSharesLockAndUpdate() { clPool := s.PrepareConcentratedPool() // Fund the owner account - s.FundAcc(test.owner, defaultPositionCoins) + s.FundAcc(test.owner, DefaultCoins) // Create a position positionId := uint64(0) liquidity := sdk.ZeroDec() if test.createFullRangePosition { var err error - positionId, _, _, liquidity, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), test.owner, defaultPositionCoins) + positionId, _, _, liquidity, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), test.owner, DefaultCoins) s.Require().NoError(err) } else { var err error @@ -1522,7 +1524,7 @@ func (s *KeeperTestSuite) TestMintSharesLockAndUpdate() { lockupModuleAccountBalancePre := s.App.LockupKeeper.GetModuleBalance(s.Ctx) // System under test - concentratedLockId, underlyingLiquidityTokenized, err := s.App.ConcentratedLiquidityKeeper.MintSharesLockAndUpdate(s.Ctx, clPool.GetId(), positionId, test.owner, test.remainingLockDuration) + concentratedLockId, underlyingLiquidityTokenized, err := s.App.ConcentratedLiquidityKeeper.MintSharesAndLock(s.Ctx, clPool.GetId(), positionId, test.owner, test.remainingLockDuration) if test.expectedErr != nil { s.Require().Error(err) s.Require().ErrorIs(err, test.expectedErr) @@ -1985,7 +1987,8 @@ func (s *KeeperTestSuite) TestGetAndUpdateFullRangeLiquidity() { s.Require().NoError(err) // Get the full range liquidity for the pool. - expectedFullRangeLiquidity := s.App.ConcentratedLiquidityKeeper.MustGetFullRangeLiquidityInPool(s.Ctx, clPoolId) + expectedFullRangeLiquidity, err := s.App.ConcentratedLiquidityKeeper.GetFullRangeLiquidityInPool(s.Ctx, clPoolId) + s.Require().NoError(err) s.Require().Equal(expectedFullRangeLiquidity, actualFullRangeLiquidity) // Create a new position that overlaps with the min tick, but is not full range and therefore should not count towards the full range liquidity. @@ -1999,7 +2002,8 @@ func (s *KeeperTestSuite) TestGetAndUpdateFullRangeLiquidity() { // Test updating the full range liquidity. err = s.App.ConcentratedLiquidityKeeper.UpdateFullRangeLiquidityInPool(s.Ctx, clPoolId, tc.updateLiquidity) s.Require().NoError(err) - actualFullRangeLiquidity = s.App.ConcentratedLiquidityKeeper.MustGetFullRangeLiquidityInPool(s.Ctx, clPoolId) + actualFullRangeLiquidity, err = s.App.ConcentratedLiquidityKeeper.GetFullRangeLiquidityInPool(s.Ctx, clPoolId) + s.Require().NoError(err) s.Require().Equal(expectedFullRangeLiquidity.Add(tc.updateLiquidity), actualFullRangeLiquidity) } } diff --git a/x/concentrated-liquidity/types/cl.go b/x/concentrated-liquidity/types/cl.go index 547bfd1933e..eb09e8260ac 100644 --- a/x/concentrated-liquidity/types/cl.go +++ b/x/concentrated-liquidity/types/cl.go @@ -17,5 +17,5 @@ func OrderInitialPoolDenoms(denom0, denom1 string) (string, string, error) { // GetConcentratedLockupDenomFromPoolId returns the concentrated lockup denom for a given pool. func GetConcentratedLockupDenomFromPoolId(poolId uint64) string { - return fmt.Sprintf("%s/%d", ClTokenPrefix, poolId) + return fmt.Sprintf("%s/%d", ConcentratedLiquidityTokenPrefix, poolId) } diff --git a/x/concentrated-liquidity/types/cl_test.go b/x/concentrated-liquidity/types/cl_test.go index 89cefc7e48e..855cee672a4 100644 --- a/x/concentrated-liquidity/types/cl_test.go +++ b/x/concentrated-liquidity/types/cl_test.go @@ -16,17 +16,17 @@ func TestGetConcentratedLockupDenomFromPoolId(t *testing.T) { { name: "poolId 1", poolId: 1, - expectedDenom: fmt.Sprintf("%s/%d", types.ClTokenPrefix, 1), + expectedDenom: fmt.Sprintf("%s/%d", types.ConcentratedLiquidityTokenPrefix, 1), }, { name: "poolId 0", poolId: 0, - expectedDenom: fmt.Sprintf("%s/%d", types.ClTokenPrefix, 0), + expectedDenom: fmt.Sprintf("%s/%d", types.ConcentratedLiquidityTokenPrefix, 0), }, { name: "poolId 1000", poolId: 1000, - expectedDenom: fmt.Sprintf("%s/%d", types.ClTokenPrefix, 1000), + expectedDenom: fmt.Sprintf("%s/%d", types.ConcentratedLiquidityTokenPrefix, 1000), }, } diff --git a/x/concentrated-liquidity/types/keys.go b/x/concentrated-liquidity/types/keys.go index 3e334e113c6..48b7b060b77 100644 --- a/x/concentrated-liquidity/types/keys.go +++ b/x/concentrated-liquidity/types/keys.go @@ -18,7 +18,7 @@ const ( uint64ByteSize = 8 uintBase = 10 - ClTokenPrefix = "cl/pool" + ConcentratedLiquidityTokenPrefix = "cl/pool" ) // Key prefixes @@ -239,7 +239,7 @@ func KeyBalancerFullRange(clPoolId, balancerPoolId, uptimeIndex uint64) []byte { // Helper Functions func GetPoolIdFromShareDenom(denom string) (uint64, error) { - if !strings.HasPrefix(denom, ClTokenPrefix) { + if !strings.HasPrefix(denom, ConcentratedLiquidityTokenPrefix) { return 0, fmt.Errorf("denom does not start with the cl token prefix") } parts := strings.Split(denom, "/") diff --git a/x/gamm/keeper/migrate.go b/x/gamm/keeper/migrate.go index 471df1df65e..0805ab7d6af 100644 --- a/x/gamm/keeper/migrate.go +++ b/x/gamm/keeper/migrate.go @@ -32,7 +32,7 @@ func (k Keeper) MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Contex } // Get the concentrated pool from the message and type cast it to ConcentratedPoolExtension. - concentratedPool, err := k.concentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, poolIdEntering) + concentratedPool, err := k.concentratedLiquidityKeeper.GetConcentratedPoolById(ctx, poolIdEntering) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err } @@ -195,7 +195,7 @@ func (k Keeper) validateRecords(ctx sdk.Context, records []types.BalancerToConce var clPool cltypes.ConcentratedPoolExtension if record.ClPoolId != 0 { // Ensure the provided ClPoolId exists and that it is of type concentrated. - clPool, err = k.concentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, record.ClPoolId) + clPool, err = k.concentratedLiquidityKeeper.GetConcentratedPoolById(ctx, record.ClPoolId) if err != nil { return err } diff --git a/x/gamm/types/expected_keepers.go b/x/gamm/types/expected_keepers.go index 33142294bd0..2984d3cbedc 100644 --- a/x/gamm/types/expected_keepers.go +++ b/x/gamm/types/expected_keepers.go @@ -49,7 +49,7 @@ type CommunityPoolKeeper interface { // ConcentratedLiquidityKeeper defines the contract needed to be fulfilled for the concentrated liquidity keeper. type ConcentratedLiquidityKeeper interface { - GetPoolFromPoolIdAndConvertToConcentrated(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) + GetConcentratedPoolById(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) CreateFullRangePosition(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, joinTime time.Time, err error) } diff --git a/x/incentives/types/expected_keepers.go b/x/incentives/types/expected_keepers.go index 76e84c1c684..4fd81e74d87 100644 --- a/x/incentives/types/expected_keepers.go +++ b/x/incentives/types/expected_keepers.go @@ -48,7 +48,7 @@ type TxFeesKeeper interface { type ConcentratedLiquidityKeeper interface { CreateIncentive(ctx sdk.Context, poolId uint64, sender sdk.AccAddress, incentiveCoin sdk.Coin, emissionRate sdk.Dec, startTime time.Time, minUptime time.Duration) (cltypes.IncentiveRecord, error) - GetPoolFromPoolIdAndConvertToConcentrated(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) + GetConcentratedPoolById(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) } type AccountKeeper interface { diff --git a/x/lockup/keeper/lock.go b/x/lockup/keeper/lock.go index da1ddb64569..076ed76537d 100644 --- a/x/lockup/keeper/lock.go +++ b/x/lockup/keeper/lock.go @@ -385,7 +385,7 @@ func (k Keeper) unlockMaturedLockInternalLogic(ctx sdk.Context, lock types.Perio coins := lock.Coins finalCoinsToSendBackToUser := sdk.NewCoins() for _, coin := range coins { - if strings.HasPrefix(coin.Denom, cltypes.ClTokenPrefix) { + if strings.HasPrefix(coin.Denom, cltypes.ConcentratedLiquidityTokenPrefix) { // If the coin is a CL liquidity token, we do not add it to the finalCoinsToSendBackToUser and instead burn it err := k.bk.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(coin)) if err != nil { diff --git a/x/lockup/keeper/lock_test.go b/x/lockup/keeper/lock_test.go index 6a803138a9f..63336318c58 100644 --- a/x/lockup/keeper/lock_test.go +++ b/x/lockup/keeper/lock_test.go @@ -913,7 +913,7 @@ func (suite *KeeperTestSuite) TestEndblockerWithdrawAllMaturedLockups() { // We expect that only non-CL locks (i.e. locks that do not have the CL token prefix) send tokens back to the user's balance when mature. This is because CL tokens get burned after the lock matures. expectedCoins := sdk.NewCoins() for _, coin := range totalCoins { - if !strings.HasPrefix(coin.Denom, cltypes.ClTokenPrefix) { + if !strings.HasPrefix(coin.Denom, cltypes.ConcentratedLiquidityTokenPrefix) { expectedCoins = expectedCoins.Add(coin) } } @@ -1068,7 +1068,7 @@ func (suite *KeeperTestSuite) TestSlashTokensFromLockByIDSendUnderlyingAndBurn() suite.Require().NoError(err) // Refetch the cl pool post full range position creation - clPool, err = suite.App.ConcentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(suite.Ctx, clPoolId) + clPool, err = suite.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(suite.Ctx, clPoolId) suite.Require().NoError(err) clPoolPositionDenom := cltypes.GetConcentratedLockupDenomFromPoolId(clPoolId) @@ -1096,7 +1096,7 @@ func (suite *KeeperTestSuite) TestSlashTokensFromLockByIDSendUnderlyingAndBurn() position, err := suite.App.ConcentratedLiquidityKeeper.GetPosition(suite.Ctx, positionID) suite.Require().NoError(err) - concentratedPool, err := suite.App.ConcentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(suite.Ctx, position.PoolId) + concentratedPool, err := suite.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(suite.Ctx, position.PoolId) suite.Require().NoError(err) tempPositionToCalculateUnderlyingAssets := position diff --git a/x/superfluid/README.md b/x/superfluid/README.md index 8ff1f497b9a..1f4c3a646d7 100644 --- a/x/superfluid/README.md +++ b/x/superfluid/README.md @@ -376,6 +376,43 @@ It then mints concentrated liquidity shares and locks them up for the staking duration. From there, the normal superfluid delegation logic is executed. +## Add To Superfluid Concentrated Position + +This message allows a user to add liquidity to a concentrated liquidity superfluid position. + +```{.go} +type MsgAddToConcentratedLiquiditySuperfluidPosition struct { + PositionId uint64 + Sender string + TokenDesired0 types.Coin + TokenDesired1 types.Coin +} +``` + +It does so by performing the following steps: +- perform validation of the input parameters + * make sure that position is locked + * belongs to the sender + * lock duration is correct and belongs to the sender +- superfluid undelegate without synthetic lock creation +- withdraw old position +- make sure position isn't the last one in pool. Fail if so +- update tokens for a new position (added + withdrawn) +- created locked SF position +- SF delegate (also creates synth lock) + +Upon successful execution, the following response is given: + +```{.go} +type MsgAddToConcentratedLiquiditySuperfluidPositionResponse struct { + PositionId uint64 + Amount0 github_com_cosmos_cosmos_sdk_types.Int + Amount1 github_com_cosmos_cosmos_sdk_types.Int + NewLiquidity github_com_cosmos_cosmos_sdk_types.Dec + LockId uint64 +} +``` + ## Epochs Overall Epoch sequence diff --git a/x/superfluid/client/cli/tx.go b/x/superfluid/client/cli/tx.go index 6f7e38137dd..9394ab92a47 100644 --- a/x/superfluid/client/cli/tx.go +++ b/x/superfluid/client/cli/tx.go @@ -221,7 +221,7 @@ func parseSetSuperfluidAssetsArgsToContent(cmd *cobra.Command) (govtypes.Content var assetType types.SuperfluidAssetType if strings.HasPrefix(asset, gammtypes.GAMMTokenPrefix) { assetType = types.SuperfluidAssetTypeLPShare - } else if strings.HasPrefix(asset, cltypes.ClTokenPrefix) { + } else if strings.HasPrefix(asset, cltypes.ConcentratedLiquidityTokenPrefix) { assetType = types.SuperfluidAssetTypeConcentratedShare } else { return nil, fmt.Errorf("Invalid asset prefix: %s", asset) diff --git a/x/superfluid/keeper/concentrated_liquidity.go b/x/superfluid/keeper/concentrated_liquidity.go index 0a2085831c8..6669ec47f8e 100644 --- a/x/superfluid/keeper/concentrated_liquidity.go +++ b/x/superfluid/keeper/concentrated_liquidity.go @@ -15,8 +15,8 @@ import ( // // Returns: // newPositionId: ID of the newly created concentrated liquidity position. -// actualAmount0: Actual amount of token 0 added. -// actualAmount1: Actual amount of token 1 added. +// actualAmount0: Actual amount of token 0 existing in the updated position. +// actualAmount1: Actual amount of token 1 existing in the updated position. // newLiquidity: The new liquidity value. // newLockId: ID of the lock associated with the new position. // error: Error, if any. @@ -24,10 +24,12 @@ import ( // An error is returned if: // - The position does not exist. // - The amount added is negative. -// - The function caller does not own the lock. +// - The provided sender does not own the lock. +// - The provided sender does not own the position. // - The position is not superfluid staked. // - The position is the last position in the pool. -func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, amount0ToAdd, amount1ToAdd sdk.Int) (uint64, sdk.Int, sdk.Int, sdk.Dec, uint64, error) { +// - The lock duration does not match the unbonding duration. +func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, sender sdk.AccAddress, positionId uint64, amount0ToAdd, amount1ToAdd sdk.Int) (uint64, sdk.Int, sdk.Int, sdk.Dec, uint64, error) { position, err := k.clk.GetPosition(ctx, positionId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err @@ -46,6 +48,11 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.PositionNotSuperfluidStakedError{PositionId: position.PositionId} } + // Defense in depth making sure that the position is full-range. + if position.LowerTick != cltypes.MinTick || position.UpperTick != cltypes.MaxTick { + return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.ConcentratedTickRangeNotFullError{ActualLowerTick: position.LowerTick, ActualUpperTick: position.UpperTick} + } + lock, err := k.lk.GetLockByID(ctx, lockId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err @@ -59,8 +66,8 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow if lock.Owner != position.Address { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: position.Address} } - if lock.Owner != owner.String() { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: owner.String()} + if lock.Owner != sender.String() { + return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: sender.String()} } unbondingDuration := k.sk.UnbondingTime(ctx) if lock.Duration != unbondingDuration || !lock.EndTime.IsZero() { @@ -69,7 +76,7 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow // Superfluid undelegate the superfluid delegated position. // This deletes the connection between the lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo. - intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, owner.String(), lockId) + intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), lockId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } @@ -81,8 +88,8 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } - // Withdraw full position. - amount0Withdrawn, amount1Withdrawn, err := k.clk.WithdrawPosition(ctx, owner, positionId, position.Liquidity) + // Withdraw full liquidity from the position. + amount0Withdrawn, amount1Withdrawn, err := k.clk.WithdrawPosition(ctx, sender, positionId, position.Liquidity) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } @@ -97,18 +104,18 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow } // Create a coins object that includes the old position coins and the new position coins. - concentratedPool, err := k.clk.GetPoolFromPoolIdAndConvertToConcentrated(ctx, position.PoolId) + concentratedPool, err := k.clk.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } newPositionCoins := sdk.NewCoins(sdk.NewCoin(concentratedPool.GetToken0(), amount0Withdrawn.Add(amount0ToAdd)), sdk.NewCoin(concentratedPool.GetToken1(), amount1Withdrawn.Add(amount1ToAdd))) // Create a full range (min to max tick) concentrated liquidity position, lock it, and superfluid delegate it. - newPositionId, actualAmount0, actualAmount1, newLiquidity, _, newLockId, err := k.clk.CreateFullRangePositionLocked(ctx, position.PoolId, owner, newPositionCoins, unbondingDuration) + newPositionId, actualNewAmount0, actualNewAmount1, newLiquidity, _, newLockId, err := k.clk.CreateFullRangePositionLocked(ctx, position.PoolId, sender, newPositionCoins, unbondingDuration) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } - err = k.SuperfluidDelegate(ctx, owner.String(), newLockId, intermediateAccount.ValAddr) + err = k.SuperfluidDelegate(ctx, sender.String(), newLockId, intermediateAccount.ValAddr) if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err } @@ -117,17 +124,18 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeySender, owner.String()), + sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), ), sdk.NewEvent( types.TypeEvtAddToConcentratedLiquiditySuperfluidPosition, - sdk.NewAttribute(sdk.AttributeKeySender, owner.String()), + sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), sdk.NewAttribute(types.AttributePositionId, strconv.FormatUint(newPositionId, 10)), - sdk.NewAttribute(types.AttributeAmount0, actualAmount0.String()), - sdk.NewAttribute(types.AttributeAmount1, actualAmount1.String()), + sdk.NewAttribute(types.AttributeAmount0, actualNewAmount0.String()), + sdk.NewAttribute(types.AttributeAmount1, actualNewAmount1.String()), sdk.NewAttribute(types.AttributeConcentratedLockId, strconv.FormatUint(newLockId, 10)), + sdk.NewAttribute(types.AttributeLiquidity, newLiquidity.String()), ), }) - return newPositionId, actualAmount0, actualAmount1, newLiquidity, newLockId, nil + return newPositionId, actualNewAmount0, actualNewAmount1, newLiquidity, newLockId, nil } diff --git a/x/superfluid/keeper/concentrated_liquidity_test.go b/x/superfluid/keeper/concentrated_liquidity_test.go index 9fc7f8b54e3..952b9820ad4 100644 --- a/x/superfluid/keeper/concentrated_liquidity_test.go +++ b/x/superfluid/keeper/concentrated_liquidity_test.go @@ -118,7 +118,7 @@ func (suite *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() // Run test setup logic. positionId, lockId, amount0, amount1, valAddr, poolJoinAcc := suite.SetupSuperfluidConcentratedPosition(ctx, tc.superfluidDelegated, tc.superfluidUndelegating, tc.unlocking, owner) - clPool, err := concentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(ctx, 1) + clPool, err := concentratedLiquidityKeeper.GetConcentratedPoolById(ctx, 1) suite.Require().NoError(err) clPoolAddress := clPool.GetAddress() diff --git a/x/superfluid/keeper/epoch.go b/x/superfluid/keeper/epoch.go index 7ce22cda1b3..4c4f461f7f3 100644 --- a/x/superfluid/keeper/epoch.go +++ b/x/superfluid/keeper/epoch.go @@ -134,7 +134,7 @@ func (k Keeper) UpdateOsmoEquivalentMultipliers(ctx sdk.Context, asset types.Sup } else if asset.AssetType == types.SuperfluidAssetTypeConcentratedShare { // LP_token_Osmo_equivalent = OSMO_amount_on_pool / LP_token_supply poolId := cltypes.MustGetPoolIdFromShareDenom(asset.Denom) - pool, err := k.clk.GetPoolFromPoolIdAndConvertToConcentrated(ctx, poolId) + pool, err := k.clk.GetConcentratedPoolById(ctx, poolId) if err != nil { k.Logger(ctx).Error(err.Error()) // Pool has unexpectedly removed Osmo from its assets. @@ -145,13 +145,19 @@ func (k Keeper) UpdateOsmoEquivalentMultipliers(ctx sdk.Context, asset types.Sup // get underlying assets from all liquidity in a full range position // note: this is not the same as the total liquidity in the pool, as this includes positions not in the full range bondDenom := k.sk.BondDenom(ctx) - fullRangeLiquidity := k.clk.MustGetFullRangeLiquidityInPool(ctx, poolId) + fullRangeLiquidity, err := k.clk.GetFullRangeLiquidityInPool(ctx, poolId) + if err != nil { + k.Logger(ctx).Error(err.Error()) + k.BeginUnwindSuperfluidAsset(ctx, 0, asset) + return fmt.Errorf("failed to retrieve full range liquidity from pool (%d): %w", poolId, err) + } position := model.Position{ LowerTick: cltypes.MinTick, UpperTick: cltypes.MaxTick, Liquidity: fullRangeLiquidity, } + // Note that the returned amounts are rounded up. This should be fine as they both are used for calculating the multiplier. asset0, asset1, err := cl.CalculateUnderlyingAssetsFromPosition(ctx, position, pool) if err != nil { k.Logger(ctx).Error(err.Error()) diff --git a/x/superfluid/keeper/gov/gov.go b/x/superfluid/keeper/gov/gov.go index 87e1ef0938b..eae3579832e 100644 --- a/x/superfluid/keeper/gov/gov.go +++ b/x/superfluid/keeper/gov/gov.go @@ -17,7 +17,7 @@ import ( func HandleSetSuperfluidAssetsProposal(ctx sdk.Context, k keeper.Keeper, ek types.EpochKeeper, p *types.SetSuperfluidAssetsProposal) error { for _, asset := range p.Assets { // Add check to ensure concentrated LP shares are formatted correctly - if strings.HasPrefix(asset.Denom, cltypes.ClTokenPrefix) { + if strings.HasPrefix(asset.Denom, cltypes.ConcentratedLiquidityTokenPrefix) { if asset.AssetType != types.SuperfluidAssetTypeConcentratedShare { return fmt.Errorf("concentrated LP share denom (%s) must have asset type %s", asset.Denom, types.SuperfluidAssetTypeConcentratedShare) } diff --git a/x/superfluid/keeper/migrate.go b/x/superfluid/keeper/migrate.go index b9a5ea10f60..2e34469df40 100644 --- a/x/superfluid/keeper/migrate.go +++ b/x/superfluid/keeper/migrate.go @@ -280,7 +280,7 @@ func (k Keeper) prepareMigration(ctx sdk.Context, sender sdk.AccAddress, lockId } // Get the concentrated pool from the provided ID and type cast it to ConcentratedPoolExtension. - concentratedPool, err = k.clk.GetPoolFromPoolIdAndConvertToConcentrated(ctx, poolIdEntering) + concentratedPool, err = k.clk.GetConcentratedPoolById(ctx, poolIdEntering) if err != nil { return 0, 0, nil, &lockuptypes.PeriodLock{}, 0, nil, false, false, err } diff --git a/x/superfluid/keeper/msg_server.go b/x/superfluid/keeper/msg_server.go index 7b9a8339ebf..7b9138b3ce5 100644 --- a/x/superfluid/keeper/msg_server.go +++ b/x/superfluid/keeper/msg_server.go @@ -237,10 +237,10 @@ func (server msgServer) AddToConcentratedLiquiditySuperfluidPosition(goCtx conte return nil, err } - newPositionId, actualAmount0, actualAmount1, _, newLockId, err := server.keeper.addToConcentratedLiquiditySuperfluidPosition(ctx, sender, msg.PositionId, msg.TokenDesired0.Amount, msg.TokenDesired1.Amount) + newPositionId, actualAmount0, actualAmount1, newLiquidity, newLockId, err := server.keeper.addToConcentratedLiquiditySuperfluidPosition(ctx, sender, msg.PositionId, msg.TokenDesired0.Amount, msg.TokenDesired1.Amount) if err != nil { return nil, err } - return &types.MsgAddToConcentratedLiquiditySuperfluidPositionResponse{PositionId: newPositionId, Amount0: actualAmount0, Amount1: actualAmount1, LockId: newLockId}, nil + return &types.MsgAddToConcentratedLiquiditySuperfluidPositionResponse{PositionId: newPositionId, Amount0: actualAmount0, Amount1: actualAmount1, LockId: newLockId, NewLiquidity: newLiquidity}, nil } diff --git a/x/superfluid/keeper/slash.go b/x/superfluid/keeper/slash.go index d08caf2ada3..3c84844281c 100644 --- a/x/superfluid/keeper/slash.go +++ b/x/superfluid/keeper/slash.go @@ -68,7 +68,7 @@ func (k Keeper) slashSynthLock(ctx sdk.Context, synthLock *lockuptypes.Synthetic // If the slashCoins contains a cl denom, we need to update the underlying cl position to reflect the slash. _ = osmoutils.ApplyFuncIfNoError(ctx, func(cacheCtx sdk.Context) error { - if strings.HasPrefix(lock.Coins[0].Denom, cltypes.ClTokenPrefix) { + if strings.HasPrefix(lock.Coins[0].Denom, cltypes.ConcentratedLiquidityTokenPrefix) { // Run prepare logic to get the underlying coins to slash. // We get the pool address here since the underlying coins will be sent directly from the pool to the community pool instead of the lock module account. // Additionally, we update the cl position's state entry to reflect the slash in the position's liquidity. @@ -109,6 +109,7 @@ func (k Keeper) prepareConcentratedLockForSlash(ctx sdk.Context, lock *lockuptyp if err != nil { return sdk.AccAddress{}, sdk.Coins{}, err } + slashAmtNeg := slashAmt.Neg() // If slashAmt is not negative, return an error @@ -121,7 +122,7 @@ func (k Keeper) prepareConcentratedLockForSlash(ctx sdk.Context, lock *lockuptyp positionForCalculatingUnderlying := position positionForCalculatingUnderlying.Liquidity = slashAmt - concentratedPool, err := k.clk.GetPoolFromPoolIdAndConvertToConcentrated(ctx, position.PoolId) + concentratedPool, err := k.clk.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { return sdk.AccAddress{}, sdk.Coins{}, err } diff --git a/x/superfluid/keeper/slash_test.go b/x/superfluid/keeper/slash_test.go index 0881819530b..8a312e67de1 100644 --- a/x/superfluid/keeper/slash_test.go +++ b/x/superfluid/keeper/slash_test.go @@ -287,7 +287,7 @@ func (suite *KeeperTestSuite) TestPrepareConcentratedLockForSlash() { upperTickInfoPostSlash, getTickErr := suite.App.ConcentratedLiquidityKeeper.GetTickInfo(suite.Ctx, clPoolId, positionPreSlash.UpperTick) suite.Require().NoError(getTickErr) - clPool, getPoolErr := suite.App.ConcentratedLiquidityKeeper.GetPoolFromPoolIdAndConvertToConcentrated(suite.Ctx, clPoolId) + clPool, getPoolErr := suite.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(suite.Ctx, clPoolId) suite.Require().NoError(getPoolErr) liquidityPostSlash := clPool.GetLiquidity() if tc.expectedErr { diff --git a/x/superfluid/keeper/stake.go b/x/superfluid/keeper/stake.go index d643ce94c9d..8ead741735f 100644 --- a/x/superfluid/keeper/stake.go +++ b/x/superfluid/keeper/stake.go @@ -301,8 +301,9 @@ func (k Keeper) SuperfluidUndelegate(ctx sdk.Context, sender string, lockID uint } // SuperfluidUndelegateToConcentratedPosition starts undelegating superfluid delegated position for the given lock. It behaves similarly to SuperfluidUndelegate, -// however it does not create a new synthetic lockup representing the unstaking side. This is because at the time this function is called, the new concentrated liquidity side -// lock has not yet been created. Once the new cl side lock is created, the synthetic lockup representing the unstaking side is created. +// however it does not create a new synthetic lockup representing the unstaking side. This is because after the time this function is called, we might +// want to perform more operations prior to creating a lock. Once the actual lock is created, the synthetic lockup representing the unstaking side +// should eventually be created as well. Use thi function with caution to avoid accidentally missing synthetic lock creation. func (k Keeper) SuperfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) { return k.undelegateCommon(ctx, sender, gammLockID) } diff --git a/x/superfluid/types/errors.go b/x/superfluid/types/errors.go index 45f8c886c8a..8fe89565f2c 100644 --- a/x/superfluid/types/errors.go +++ b/x/superfluid/types/errors.go @@ -4,6 +4,8 @@ import ( fmt "fmt" errorsmod "cosmossdk.io/errors" + + cltypes "github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/types" ) // x/superfluid module errors. @@ -51,3 +53,12 @@ type LockOwnerMismatchError struct { func (e LockOwnerMismatchError) Error() string { return fmt.Sprintf("lock ID %d owner %s does not match provided owner %s.", e.LockId, e.LockOwner, e.ProvidedOwner) } + +type ConcentratedTickRangeNotFullError struct { + ActualLowerTick int64 + ActualUpperTick int64 +} + +func (e ConcentratedTickRangeNotFullError) Error() string { + return fmt.Sprintf("position must be full range. Lower tick (%d) must be (%d). Upper tick (%d) must be (%d)", e.ActualLowerTick, e.ActualUpperTick, cltypes.MinTick, cltypes.MaxTick) +} diff --git a/x/superfluid/types/expected_keepers.go b/x/superfluid/types/expected_keepers.go index f82a4f74f04..24bba8eb954 100644 --- a/x/superfluid/types/expected_keepers.go +++ b/x/superfluid/types/expected_keepers.go @@ -106,11 +106,11 @@ type ConcentratedKeeper interface { GetPosition(ctx sdk.Context, positionId uint64) (model.Position, error) SetPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64, joinTime time.Time, liquidity sdk.Dec, positionId uint64, underlyingLockId uint64) error UpdatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, lowerTick, upperTick int64, liquidityDelta sdk.Dec, joinTime time.Time, positionId uint64) (sdk.Int, sdk.Int, error) - GetPoolFromPoolIdAndConvertToConcentrated(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) + GetConcentratedPoolById(ctx sdk.Context, poolId uint64) (cltypes.ConcentratedPoolExtension, error) CreateFullRangePositionLocked(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, joinTime time.Time, concentratedLockID uint64, err error) CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, joinTime time.Time, concentratedLockID uint64, err error) GetPositionIdToLockId(ctx sdk.Context, underlyingLockId uint64) (uint64, error) - MustGetFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64) sdk.Dec + GetFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64) (sdk.Dec, error) PositionHasActiveUnderlyingLock(ctx sdk.Context, positionId uint64) (bool, uint64, error) HasAnyPositionForPool(ctx sdk.Context, poolId uint64) (bool, error) WithdrawPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, requestedLiquidityAmountToWithdraw sdk.Dec) (amtDenom0, amtDenom1 sdk.Int, err error) diff --git a/x/superfluid/types/gov.go b/x/superfluid/types/gov.go index c34c3e8c066..1ad7dd8de97 100644 --- a/x/superfluid/types/gov.go +++ b/x/superfluid/types/gov.go @@ -71,7 +71,7 @@ func (p *SetSuperfluidAssetsProposal) ValidateBasic() error { return err } // Denom must be from CL - if !strings.HasPrefix(asset.Denom, cltypes.ClTokenPrefix) { + if !strings.HasPrefix(asset.Denom, cltypes.ConcentratedLiquidityTokenPrefix) { return fmt.Errorf("denom %s must be from CL", asset.Denom) } default: diff --git a/x/superfluid/types/tx.pb.go b/x/superfluid/types/tx.pb.go index 786cc740f9b..1d8fa701c2f 100644 --- a/x/superfluid/types/tx.pb.go +++ b/x/superfluid/types/tx.pb.go @@ -962,7 +962,11 @@ type MsgAddToConcentratedLiquiditySuperfluidPositionResponse struct { PositionId uint64 `protobuf:"varint,1,opt,name=position_id,json=positionId,proto3" json:"position_id,omitempty" yaml:"position_id"` Amount0 github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=amount0,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount0" yaml:"amount0"` Amount1 github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount1,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount1" yaml:"amount1"` - LockId uint64 `protobuf:"varint,4,opt,name=lock_id,json=lockId,proto3" json:"lock_id,omitempty" yaml:"lock_id"` + // new_liquidity is the final liquidity after the add. + // It includes the liquidity that existed before in the position + // and the new liquidity that was added to the position. + NewLiquidity github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=new_liquidity,json=newLiquidity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"new_liquidity" yaml:"new_liquidity"` + LockId uint64 `protobuf:"varint,4,opt,name=lock_id,json=lockId,proto3" json:"lock_id,omitempty" yaml:"lock_id"` } func (m *MsgAddToConcentratedLiquiditySuperfluidPositionResponse) Reset() { @@ -1040,81 +1044,83 @@ func init() { func init() { proto.RegisterFile("osmosis/superfluid/tx.proto", fileDescriptor_55b645f187d22814) } var fileDescriptor_55b645f187d22814 = []byte{ - // 1173 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0x41, 0x4f, 0x1b, 0x47, - 0x14, 0x66, 0x6d, 0x17, 0x92, 0xa1, 0x90, 0xb0, 0x0d, 0x89, 0x71, 0x89, 0xd7, 0x99, 0x46, 0x11, - 0x55, 0xc8, 0x2e, 0x26, 0x4d, 0x40, 0x3d, 0x81, 0xb1, 0x5a, 0x39, 0xc5, 0x2a, 0xda, 0x80, 0x2a, - 0x45, 0xaa, 0x56, 0x6b, 0xcf, 0x64, 0xd9, 0xb2, 0xde, 0x71, 0x76, 0xc6, 0x14, 0xd4, 0x1f, 0x90, - 0x6b, 0xfe, 0x41, 0xef, 0x3d, 0xf4, 0x37, 0xf4, 0xd6, 0xa8, 0xa7, 0xdc, 0x5a, 0xb5, 0x92, 0x53, - 0xc1, 0x3f, 0xe0, 0xd8, 0x53, 0x35, 0xbb, 0xb3, 0xeb, 0x35, 0x78, 0x31, 0xeb, 0x90, 0x43, 0x4e, - 0xec, 0xcc, 0xbc, 0xf7, 0x7d, 0xef, 0xbd, 0x79, 0xef, 0xcd, 0xc3, 0xe0, 0x53, 0x42, 0x5b, 0x84, - 0xda, 0x54, 0xa3, 0x9d, 0x36, 0xf6, 0x9e, 0x3b, 0x1d, 0x1b, 0x69, 0xec, 0x40, 0x6d, 0x7b, 0x84, - 0x11, 0x59, 0x16, 0x87, 0x6a, 0xef, 0xb0, 0x70, 0xc3, 0x22, 0x16, 0xf1, 0x8f, 0x35, 0xfe, 0x15, - 0x48, 0x16, 0x8a, 0x16, 0x21, 0x96, 0x83, 0x35, 0x7f, 0xd5, 0xe8, 0x3c, 0xd7, 0x50, 0xc7, 0x33, - 0x99, 0x4d, 0xdc, 0xf0, 0xbc, 0xe9, 0x43, 0x69, 0x0d, 0x93, 0x62, 0x6d, 0xbf, 0xdc, 0xc0, 0xcc, - 0x2c, 0x6b, 0x4d, 0x62, 0x87, 0xe7, 0xca, 0x69, 0x7d, 0x66, 0xb7, 0x30, 0x65, 0x66, 0xab, 0x2d, - 0x04, 0x3e, 0x1b, 0x60, 0x67, 0xef, 0x33, 0x10, 0x82, 0xfb, 0x60, 0xb6, 0x4e, 0xad, 0xa7, 0xd1, - 0x76, 0x15, 0x3b, 0xd8, 0x32, 0x19, 0x96, 0x3f, 0x07, 0xe3, 0x14, 0xbb, 0x08, 0x7b, 0x79, 0xa9, - 0x24, 0x2d, 0x5c, 0xad, 0xcc, 0x9c, 0x74, 0x95, 0xa9, 0x43, 0xb3, 0xe5, 0x7c, 0x09, 0x83, 0x7d, - 0xa8, 0x0b, 0x01, 0xf9, 0x16, 0x98, 0x70, 0x48, 0x73, 0xcf, 0xb0, 0x51, 0x3e, 0x53, 0x92, 0x16, - 0x72, 0xfa, 0x38, 0x5f, 0xd6, 0x90, 0x3c, 0x07, 0xae, 0xec, 0x9b, 0x8e, 0x61, 0x22, 0xe4, 0xe5, - 0xb3, 0x1c, 0x45, 0x9f, 0xd8, 0x37, 0x9d, 0x75, 0x84, 0x3c, 0xa8, 0x80, 0xdb, 0x03, 0x79, 0x75, - 0x4c, 0xdb, 0xc4, 0xa5, 0x18, 0x7e, 0x0f, 0x6e, 0xf5, 0x09, 0xec, 0xb8, 0xe8, 0x12, 0x4d, 0x83, - 0x77, 0x80, 0x92, 0x00, 0x7f, 0x8e, 0x05, 0x0d, 0xe2, 0xa2, 0x4d, 0xd2, 0xdc, 0x7b, 0x4f, 0x16, - 0x84, 0xf0, 0x91, 0x05, 0xbf, 0x4a, 0xe0, 0x6e, 0x82, 0x95, 0xeb, 0xee, 0x25, 0xdb, 0x23, 0x57, - 0x40, 0x8e, 0x67, 0x97, 0x7f, 0x51, 0x93, 0xcb, 0x73, 0x6a, 0x90, 0x7e, 0x2a, 0x4f, 0x3f, 0x55, - 0xa4, 0x9f, 0xba, 0x41, 0x6c, 0xb7, 0xf2, 0xc9, 0xeb, 0xae, 0x32, 0x76, 0xd2, 0x55, 0x26, 0x03, - 0x02, 0xae, 0x04, 0x75, 0x5f, 0x17, 0x7e, 0x0d, 0x16, 0x2f, 0x62, 0x6f, 0xe8, 0x60, 0xdc, 0x18, - 0xa9, 0x2f, 0x38, 0xbf, 0x4b, 0x60, 0xbe, 0x4e, 0x2d, 0x2e, 0xbc, 0xee, 0xa2, 0x77, 0x4b, 0x4f, - 0x13, 0x7c, 0xc4, 0x8d, 0xa3, 0xf9, 0x4c, 0x29, 0x7b, 0xbe, 0x67, 0x4b, 0xdc, 0xb3, 0x5f, 0xde, - 0x2a, 0x0b, 0x96, 0xcd, 0x76, 0x3b, 0x0d, 0xb5, 0x49, 0x5a, 0x9a, 0xa8, 0xc2, 0xe0, 0xcf, 0x03, - 0x8a, 0xf6, 0x34, 0x76, 0xd8, 0xc6, 0xd4, 0x57, 0xa0, 0x7a, 0x80, 0x7c, 0x5e, 0xa2, 0x3f, 0xf6, - 0xaf, 0x30, 0xd1, 0x91, 0x28, 0x14, 0xd3, 0x20, 0x53, 0xab, 0x8a, 0x28, 0x64, 0x6a, 0x55, 0xf8, - 0x32, 0x03, 0xb4, 0x3a, 0xb5, 0x36, 0x3c, 0x6c, 0x32, 0xfc, 0x55, 0xc7, 0x71, 0x74, 0xd3, 0xb5, - 0xf0, 0x16, 0xa1, 0x36, 0xef, 0x11, 0x1f, 0x76, 0x50, 0xe4, 0xfb, 0x60, 0xa2, 0x4d, 0x88, 0xc3, - 0xef, 0x3d, 0xc7, 0x3d, 0xae, 0xc8, 0x27, 0x5d, 0x65, 0x3a, 0xb0, 0x54, 0x1c, 0x40, 0x7d, 0x9c, - 0x7f, 0xd5, 0x10, 0x7c, 0x01, 0x56, 0x52, 0x06, 0x22, 0x0a, 0xea, 0x4d, 0x10, 0x24, 0x54, 0xb5, - 0x2f, 0xbd, 0xaa, 0x72, 0x11, 0x80, 0xb6, 0x00, 0xa8, 0x55, 0x45, 0x1d, 0xc4, 0x76, 0xa0, 0x07, - 0xf2, 0x75, 0x6a, 0xed, 0xb8, 0x5b, 0x84, 0x38, 0xdf, 0xed, 0xda, 0x0c, 0x3b, 0x36, 0x65, 0x18, - 0xf1, 0x65, 0x9a, 0x20, 0xc7, 0xdc, 0xcc, 0x0c, 0x75, 0xf3, 0x09, 0x28, 0x25, 0x71, 0x46, 0xfe, - 0xdc, 0x03, 0xd7, 0xf0, 0x81, 0xcd, 0x30, 0x32, 0x44, 0xd9, 0xd0, 0xbc, 0x54, 0xca, 0x2e, 0xe4, - 0xf4, 0xa9, 0x60, 0x7b, 0xd3, 0xaf, 0x1e, 0x0a, 0x8f, 0x32, 0x60, 0xd5, 0x07, 0x73, 0x82, 0xbc, - 0xab, 0xdb, 0x96, 0x67, 0x32, 0xfc, 0x74, 0xd7, 0xf4, 0x30, 0xdd, 0x26, 0x51, 0x14, 0x37, 0x88, - 0xdb, 0xc4, 0x2e, 0xe3, 0x67, 0x28, 0x8c, 0x68, 0x4a, 0x07, 0xfb, 0x9a, 0x49, 0xdc, 0x41, 0x71, - 0x00, 0xa3, 0x06, 0x63, 0x81, 0x19, 0xea, 0x1b, 0x60, 0x30, 0x62, 0xb4, 0x02, 0x8b, 0x86, 0x77, - 0x9b, 0x92, 0xe8, 0x36, 0x79, 0x61, 0xc1, 0x69, 0x04, 0xa8, 0x5f, 0xa3, 0xc2, 0x2d, 0xe1, 0xa5, - 0x8c, 0xc1, 0x34, 0x23, 0x7b, 0xd8, 0x35, 0x48, 0x87, 0x19, 0x2d, 0x9e, 0xe4, 0xb9, 0x61, 0x49, - 0x7e, 0x57, 0xb0, 0xcc, 0x07, 0x2c, 0x7d, 0xea, 0x86, 0xd9, 0x22, 0x1d, 0x97, 0x51, 0xa8, 0x7f, - 0xec, 0xef, 0x7f, 0xdb, 0x61, 0x75, 0xdb, 0xa5, 0xf0, 0x8f, 0x2c, 0x58, 0x1b, 0x35, 0xc8, 0xd1, - 0x8d, 0x3e, 0x03, 0x13, 0x01, 0xfc, 0x92, 0x88, 0xf6, 0x1a, 0xb7, 0xe4, 0xef, 0xae, 0x72, 0xef, - 0x02, 0xe5, 0x56, 0x73, 0x59, 0x2f, 0xde, 0x02, 0x06, 0xea, 0x21, 0x60, 0x0f, 0xbb, 0xec, 0xdf, - 0xce, 0x3b, 0x63, 0x97, 0x23, 0xec, 0xb2, 0xfc, 0x23, 0x98, 0x71, 0xec, 0x17, 0x1d, 0x1b, 0xd9, - 0xec, 0xd0, 0x68, 0xfa, 0xb5, 0x89, 0x82, 0x2a, 0xaf, 0x3c, 0x49, 0xc1, 0x52, 0xc5, 0xcd, 0xde, - 0xdd, 0x9e, 0x01, 0x84, 0xfa, 0xf5, 0x68, 0x2f, 0xa8, 0x7f, 0x24, 0xef, 0x80, 0xab, 0x3f, 0x10, - 0xdb, 0x35, 0xf8, 0xb4, 0xe3, 0x37, 0x8f, 0xc9, 0xe5, 0x82, 0x1a, 0x8c, 0x42, 0x6a, 0x38, 0x0a, - 0xa9, 0xdb, 0xe1, 0x28, 0x54, 0x99, 0x17, 0x17, 0x7b, 0x3d, 0xa0, 0x88, 0x54, 0xe1, 0xab, 0xb7, - 0x8a, 0xa4, 0x5f, 0xe1, 0x6b, 0x2e, 0x0c, 0xff, 0x0c, 0xda, 0xed, 0x3a, 0x42, 0xdb, 0x24, 0x7e, - 0x61, 0x9b, 0x21, 0x7f, 0xaf, 0xcb, 0x44, 0x85, 0xb2, 0x02, 0x26, 0xc3, 0x9e, 0x11, 0xbd, 0x60, - 0x95, 0x9b, 0x27, 0x5d, 0x45, 0x0e, 0x4b, 0x3c, 0x3a, 0x84, 0xb1, 0xf6, 0x82, 0x62, 0x15, 0x96, - 0x19, 0x56, 0x61, 0x46, 0x98, 0xcb, 0x08, 0x53, 0xdb, 0xc3, 0x68, 0x69, 0x78, 0xc5, 0xdc, 0x16, - 0x2e, 0xcf, 0xc6, 0x73, 0x39, 0x54, 0x87, 0xfa, 0x94, 0xbf, 0x51, 0x15, 0xeb, 0x33, 0x04, 0x65, - 0x11, 0xd4, 0x11, 0x09, 0xca, 0xa7, 0x08, 0xca, 0x3c, 0xb2, 0x2b, 0x29, 0x23, 0x1b, 0x55, 0xc7, - 0xc8, 0x11, 0x8e, 0x95, 0x55, 0xe6, 0x3d, 0x96, 0x55, 0xf6, 0xb2, 0xcb, 0x2a, 0xd6, 0x50, 0x73, - 0xc3, 0x1a, 0xea, 0xf2, 0x7f, 0x00, 0x64, 0xeb, 0xd4, 0x92, 0x3d, 0x20, 0x0f, 0x1a, 0x06, 0xd4, - 0xb3, 0xff, 0x8a, 0xa8, 0x03, 0x67, 0xee, 0x42, 0xf9, 0xc2, 0xa2, 0xd1, 0xcd, 0x1c, 0x80, 0x1b, - 0x03, 0x67, 0xf3, 0xfb, 0x43, 0xa1, 0x7a, 0xc2, 0x85, 0x87, 0x29, 0x84, 0x93, 0x98, 0xa3, 0x19, - 0xf8, 0x22, 0xcc, 0xa1, 0xf0, 0x85, 0x98, 0xcf, 0x4c, 0xab, 0x3f, 0x4b, 0xe0, 0xce, 0xf0, 0x59, - 0x7c, 0x35, 0x85, 0x53, 0x7d, 0x9a, 0x85, 0xb5, 0x51, 0x35, 0x23, 0x0b, 0x5f, 0x4a, 0x60, 0x2e, - 0x79, 0x66, 0x5e, 0x4a, 0xc0, 0x4f, 0xd4, 0x28, 0xac, 0xa6, 0xd5, 0x88, 0x2c, 0xf9, 0x4d, 0x02, - 0x8b, 0xa9, 0x66, 0xd7, 0x8d, 0x04, 0xaa, 0x34, 0x20, 0x85, 0x6f, 0x2e, 0x01, 0x24, 0x72, 0xe1, - 0x27, 0x30, 0x3b, 0x78, 0x02, 0x5c, 0x4c, 0x60, 0x19, 0x28, 0x5d, 0xf8, 0x22, 0x8d, 0x74, 0x44, - 0xfe, 0x8f, 0x04, 0x1e, 0x8d, 0x36, 0xbe, 0x6d, 0x26, 0xf2, 0x8d, 0x80, 0x56, 0xd8, 0xbe, 0x4c, - 0xb4, 0xbe, 0xec, 0x48, 0xf5, 0xd4, 0x26, 0x65, 0x47, 0x1a, 0x90, 0xc4, 0xec, 0x18, 0xe5, 0x69, - 0xaa, 0x6c, 0xbd, 0x3e, 0x2a, 0x4a, 0x6f, 0x8e, 0x8a, 0xd2, 0xbf, 0x47, 0x45, 0xe9, 0xd5, 0x71, - 0x71, 0xec, 0xcd, 0x71, 0x71, 0xec, 0xaf, 0xe3, 0xe2, 0xd8, 0xb3, 0xc7, 0xb1, 0x67, 0x40, 0x10, - 0x3e, 0x70, 0xcc, 0x06, 0x0d, 0x17, 0xda, 0x7e, 0xf9, 0x91, 0x76, 0xd0, 0xf7, 0xeb, 0x11, 0x7f, - 0x1a, 0x1a, 0xe3, 0xfe, 0xf8, 0xf2, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x23, 0xf9, - 0xff, 0x60, 0x12, 0x00, 0x00, + // 1204 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0xcd, 0x6e, 0xdb, 0x46, + 0x10, 0x36, 0x25, 0xc5, 0x4e, 0xd6, 0x71, 0x7e, 0xd8, 0x38, 0x91, 0x55, 0x47, 0x54, 0xb6, 0x41, + 0xe0, 0x22, 0x0e, 0x69, 0x39, 0x4d, 0x62, 0xf4, 0x64, 0xcb, 0x42, 0x0a, 0xa5, 0x16, 0x6a, 0x30, + 0x36, 0x0a, 0x04, 0x28, 0x08, 0x4a, 0xbb, 0xa1, 0x59, 0x53, 0x5c, 0x85, 0xbb, 0xf2, 0x0f, 0xfa, + 0x00, 0xb9, 0xe6, 0x0d, 0x7a, 0xef, 0xa1, 0xcf, 0xd0, 0x43, 0x81, 0x06, 0x3d, 0xe5, 0xd6, 0xa2, + 0x05, 0x94, 0xc2, 0x7e, 0x03, 0x1f, 0x7b, 0x2a, 0x48, 0x2e, 0x57, 0x94, 0x2d, 0x5a, 0xa6, 0xe2, + 0x1c, 0x7a, 0x32, 0x77, 0x77, 0xe6, 0xfb, 0x66, 0x66, 0x67, 0x66, 0x47, 0x06, 0x9f, 0x12, 0xda, + 0x22, 0xd4, 0xa6, 0x1a, 0xed, 0xb4, 0xb1, 0xf7, 0xd2, 0xe9, 0xd8, 0x48, 0x63, 0x7b, 0x6a, 0xdb, + 0x23, 0x8c, 0xc8, 0x32, 0x3f, 0x54, 0x7b, 0x87, 0x85, 0x1b, 0x16, 0xb1, 0x48, 0x70, 0xac, 0xf9, + 0x5f, 0xa1, 0x64, 0xa1, 0x68, 0x11, 0x62, 0x39, 0x58, 0x0b, 0x56, 0x8d, 0xce, 0x4b, 0x0d, 0x75, + 0x3c, 0x93, 0xd9, 0xc4, 0x8d, 0xce, 0x9b, 0x01, 0x94, 0xd6, 0x30, 0x29, 0xd6, 0x76, 0xca, 0x0d, + 0xcc, 0xcc, 0xb2, 0xd6, 0x24, 0x76, 0x74, 0xae, 0x1c, 0xd7, 0x67, 0x76, 0x0b, 0x53, 0x66, 0xb6, + 0xda, 0x5c, 0xe0, 0xb3, 0x01, 0x76, 0xf6, 0x3e, 0x43, 0x21, 0xb8, 0x03, 0xa6, 0xeb, 0xd4, 0x7a, + 0x2e, 0xb6, 0xab, 0xd8, 0xc1, 0x96, 0xc9, 0xb0, 0xfc, 0x39, 0x18, 0xa7, 0xd8, 0x45, 0xd8, 0xcb, + 0x4b, 0x25, 0x69, 0xee, 0x52, 0xe5, 0xfa, 0x51, 0x57, 0x99, 0xda, 0x37, 0x5b, 0xce, 0x97, 0x30, + 0xdc, 0x87, 0x3a, 0x17, 0x90, 0x6f, 0x81, 0x09, 0x87, 0x34, 0xb7, 0x0d, 0x1b, 0xe5, 0x33, 0x25, + 0x69, 0x2e, 0xa7, 0x8f, 0xfb, 0xcb, 0x1a, 0x92, 0x67, 0xc0, 0xc5, 0x1d, 0xd3, 0x31, 0x4c, 0x84, + 0xbc, 0x7c, 0xd6, 0x47, 0xd1, 0x27, 0x76, 0x4c, 0x67, 0x05, 0x21, 0x0f, 0x2a, 0xe0, 0xf6, 0x40, + 0x5e, 0x1d, 0xd3, 0x36, 0x71, 0x29, 0x86, 0xdf, 0x81, 0x5b, 0x7d, 0x02, 0x9b, 0x2e, 0x3a, 0x47, + 0xd3, 0xe0, 0x1d, 0xa0, 0x24, 0xc0, 0x9f, 0x62, 0x41, 0x83, 0xb8, 0x68, 0x8d, 0x34, 0xb7, 0x3f, + 0x92, 0x05, 0x11, 0xbc, 0xb0, 0xe0, 0x67, 0x09, 0xdc, 0x4d, 0xb0, 0x72, 0xc5, 0x3d, 0x67, 0x7b, + 0xe4, 0x0a, 0xc8, 0xf9, 0xd9, 0x15, 0x5c, 0xd4, 0xe4, 0xe2, 0x8c, 0x1a, 0xa6, 0x9f, 0xea, 0xa7, + 0x9f, 0xca, 0xd3, 0x4f, 0x5d, 0x25, 0xb6, 0x5b, 0xf9, 0xe4, 0x6d, 0x57, 0x19, 0x3b, 0xea, 0x2a, + 0x93, 0x21, 0x81, 0xaf, 0x04, 0xf5, 0x40, 0x17, 0x7e, 0x05, 0xe6, 0xcf, 0x62, 0x6f, 0xe4, 0x60, + 0xdc, 0x18, 0xa9, 0x2f, 0x38, 0xbf, 0x49, 0x60, 0xb6, 0x4e, 0x2d, 0x5f, 0x78, 0xc5, 0x45, 0x1f, + 0x96, 0x9e, 0x26, 0xb8, 0xe0, 0x1b, 0x47, 0xf3, 0x99, 0x52, 0xf6, 0x74, 0xcf, 0x16, 0x7c, 0xcf, + 0x7e, 0x7a, 0xaf, 0xcc, 0x59, 0x36, 0xdb, 0xea, 0x34, 0xd4, 0x26, 0x69, 0x69, 0xbc, 0x0a, 0xc3, + 0x3f, 0x0f, 0x28, 0xda, 0xd6, 0xd8, 0x7e, 0x1b, 0xd3, 0x40, 0x81, 0xea, 0x21, 0xf2, 0x69, 0x89, + 0xfe, 0x38, 0xb8, 0xc2, 0x44, 0x47, 0x44, 0x28, 0xae, 0x80, 0x4c, 0xad, 0xca, 0xa3, 0x90, 0xa9, + 0x55, 0xe1, 0xeb, 0x0c, 0xd0, 0xea, 0xd4, 0x5a, 0xf5, 0xb0, 0xc9, 0xf0, 0xd3, 0x8e, 0xe3, 0xe8, + 0xa6, 0x6b, 0xe1, 0x75, 0x42, 0x6d, 0xbf, 0x47, 0xfc, 0xbf, 0x83, 0x22, 0xdf, 0x07, 0x13, 0x6d, + 0x42, 0x1c, 0xff, 0xde, 0x73, 0xbe, 0xc7, 0x15, 0xf9, 0xa8, 0xab, 0x5c, 0x09, 0x2d, 0xe5, 0x07, + 0x50, 0x1f, 0xf7, 0xbf, 0x6a, 0x08, 0xbe, 0x02, 0x4f, 0x52, 0x06, 0x42, 0x04, 0xf5, 0x26, 0x08, + 0x13, 0xaa, 0xda, 0x97, 0x5e, 0x55, 0xb9, 0x08, 0x40, 0x9b, 0x03, 0xd4, 0xaa, 0xbc, 0x0e, 0x62, + 0x3b, 0xd0, 0x03, 0xf9, 0x3a, 0xb5, 0x36, 0xdd, 0x75, 0x42, 0x9c, 0x6f, 0xb7, 0x6c, 0x86, 0x1d, + 0x9b, 0x32, 0x8c, 0xfc, 0x65, 0x9a, 0x20, 0xc7, 0xdc, 0xcc, 0x0c, 0x75, 0xf3, 0x19, 0x28, 0x25, + 0x71, 0x0a, 0x7f, 0xee, 0x81, 0xab, 0x78, 0xcf, 0x66, 0x18, 0x19, 0xbc, 0x6c, 0x68, 0x5e, 0x2a, + 0x65, 0xe7, 0x72, 0xfa, 0x54, 0xb8, 0xbd, 0x16, 0x54, 0x0f, 0x85, 0x07, 0x19, 0xb0, 0x14, 0x80, + 0x39, 0x61, 0xde, 0xd5, 0x6d, 0xcb, 0x33, 0x19, 0x7e, 0xbe, 0x65, 0x7a, 0x98, 0x6e, 0x10, 0x11, + 0xc5, 0x55, 0xe2, 0x36, 0xb1, 0xcb, 0xfc, 0x33, 0x14, 0x45, 0x34, 0xa5, 0x83, 0x7d, 0xcd, 0x24, + 0xee, 0x20, 0x3f, 0x80, 0xa2, 0xc1, 0x58, 0xe0, 0x3a, 0x0d, 0x0c, 0x30, 0x18, 0x31, 0x5a, 0xa1, + 0x45, 0xc3, 0xbb, 0x4d, 0x89, 0x77, 0x9b, 0x3c, 0xb7, 0xe0, 0x38, 0x02, 0xd4, 0xaf, 0x52, 0xee, + 0x16, 0xf7, 0x52, 0xc6, 0xe0, 0x0a, 0x23, 0xdb, 0xd8, 0x35, 0x48, 0x87, 0x19, 0x2d, 0x3f, 0xc9, + 0x73, 0xc3, 0x92, 0xfc, 0x2e, 0x67, 0x99, 0x0d, 0x59, 0xfa, 0xd4, 0x0d, 0xb3, 0x45, 0x3a, 0x2e, + 0xa3, 0x50, 0xbf, 0x1c, 0xec, 0x7f, 0xd3, 0x61, 0x75, 0xdb, 0xa5, 0xf0, 0xf7, 0x2c, 0x58, 0x1e, + 0x35, 0xc8, 0xe2, 0x46, 0x5f, 0x80, 0x89, 0x10, 0x7e, 0x81, 0x47, 0x7b, 0xd9, 0xb7, 0xe4, 0xaf, + 0xae, 0x72, 0xef, 0x0c, 0xe5, 0x56, 0x73, 0x59, 0x2f, 0xde, 0x1c, 0x06, 0xea, 0x11, 0x60, 0x0f, + 0xbb, 0x1c, 0xdc, 0xce, 0x07, 0x63, 0x97, 0x05, 0x76, 0x59, 0xde, 0x05, 0xd7, 0x1d, 0xfb, 0x55, + 0xc7, 0x46, 0x36, 0xdb, 0x37, 0x9a, 0x41, 0x6d, 0xa2, 0xb0, 0xca, 0x2b, 0xcf, 0x52, 0xb0, 0x54, + 0x71, 0xb3, 0x77, 0xb7, 0x27, 0x00, 0xa1, 0x7e, 0x4d, 0xec, 0x85, 0xf5, 0x8f, 0xe4, 0x4d, 0x70, + 0xe9, 0x7b, 0x62, 0xbb, 0x86, 0x3f, 0xed, 0x04, 0xcd, 0x63, 0x72, 0xb1, 0xa0, 0x86, 0xa3, 0x90, + 0x1a, 0x8d, 0x42, 0xea, 0x46, 0x34, 0x0a, 0x55, 0x66, 0xf9, 0xc5, 0x5e, 0x0b, 0x29, 0x84, 0x2a, + 0x7c, 0xf3, 0x5e, 0x91, 0xf4, 0x8b, 0xfe, 0xda, 0x17, 0x86, 0x7f, 0x84, 0xed, 0x76, 0x05, 0xa1, + 0x0d, 0x12, 0xbf, 0xb0, 0xb5, 0x88, 0xbf, 0xd7, 0x65, 0x44, 0xa1, 0x3c, 0x01, 0x93, 0x51, 0xcf, + 0x10, 0x2f, 0x58, 0xe5, 0xe6, 0x51, 0x57, 0x91, 0xa3, 0x12, 0x17, 0x87, 0x30, 0xd6, 0x5e, 0x50, + 0xac, 0xc2, 0x32, 0xc3, 0x2a, 0xcc, 0x88, 0x72, 0x19, 0x61, 0x6a, 0x7b, 0x18, 0x2d, 0x0c, 0xaf, + 0x98, 0xdb, 0xdc, 0xe5, 0xe9, 0x78, 0x2e, 0x47, 0xea, 0x50, 0x9f, 0x0a, 0x36, 0xaa, 0x7c, 0x7d, + 0x82, 0xa0, 0xcc, 0x83, 0x3a, 0x22, 0x41, 0xf9, 0x18, 0x41, 0x19, 0xfe, 0x9a, 0x0d, 0xfa, 0x77, + 0x9a, 0xc8, 0x8a, 0xea, 0x18, 0x39, 0xc2, 0xb1, 0xb2, 0xca, 0x7c, 0xc4, 0xb2, 0xca, 0x9e, 0x77, + 0x59, 0x6d, 0x83, 0x29, 0x17, 0xef, 0x1a, 0x22, 0xeb, 0xf3, 0x17, 0x02, 0x86, 0xa7, 0xa9, 0x4b, + 0xea, 0x46, 0xc8, 0xd0, 0x07, 0x06, 0xf5, 0xcb, 0x2e, 0xde, 0x15, 0x71, 0x8f, 0x77, 0xef, 0xdc, + 0xb0, 0xee, 0xbd, 0xf8, 0x2f, 0x00, 0xd9, 0x3a, 0xb5, 0x64, 0x0f, 0xc8, 0x83, 0x26, 0x0f, 0xf5, + 0xe4, 0xef, 0x1e, 0x75, 0xe0, 0x80, 0x5f, 0x28, 0x9f, 0x59, 0x54, 0xa4, 0xc1, 0x1e, 0xb8, 0x31, + 0xf0, 0x87, 0xc0, 0xfd, 0xa1, 0x50, 0x3d, 0xe1, 0xc2, 0xc3, 0x14, 0xc2, 0x49, 0xcc, 0x62, 0xe0, + 0x3e, 0x0b, 0x73, 0x24, 0x7c, 0x26, 0xe6, 0x13, 0xa3, 0xf1, 0x8f, 0x12, 0xb8, 0x33, 0x7c, 0xf0, + 0x5f, 0x4a, 0xe1, 0x54, 0x9f, 0x66, 0x61, 0x79, 0x54, 0x4d, 0x61, 0xe1, 0x6b, 0x09, 0xcc, 0x24, + 0x0f, 0xe8, 0x0b, 0x09, 0xf8, 0x89, 0x1a, 0x85, 0xa5, 0xb4, 0x1a, 0xc2, 0x92, 0x5f, 0x24, 0x30, + 0x9f, 0x6a, 0x50, 0x5e, 0x4d, 0xa0, 0x4a, 0x03, 0x52, 0xf8, 0xfa, 0x1c, 0x40, 0x84, 0x0b, 0x3f, + 0x80, 0xe9, 0xc1, 0xe3, 0xe6, 0x7c, 0x02, 0xcb, 0x40, 0xe9, 0xc2, 0x17, 0x69, 0xa4, 0x05, 0xf9, + 0xdf, 0x12, 0x78, 0x34, 0xda, 0xac, 0xb8, 0x96, 0xc8, 0x37, 0x02, 0x5a, 0x61, 0xe3, 0x3c, 0xd1, + 0xfa, 0xb2, 0x23, 0xd5, 0xbb, 0x9e, 0x94, 0x1d, 0x69, 0x40, 0x12, 0xb3, 0x63, 0x94, 0x77, 0xb0, + 0xb2, 0xfe, 0xf6, 0xa0, 0x28, 0xbd, 0x3b, 0x28, 0x4a, 0xff, 0x1c, 0x14, 0xa5, 0x37, 0x87, 0xc5, + 0xb1, 0x77, 0x87, 0xc5, 0xb1, 0x3f, 0x0f, 0x8b, 0x63, 0x2f, 0x1e, 0xc7, 0x5e, 0x04, 0x4e, 0xf8, + 0xc0, 0x31, 0x1b, 0x34, 0x5a, 0x68, 0x3b, 0xe5, 0x47, 0xda, 0x5e, 0xdf, 0xbf, 0xaa, 0xfc, 0x57, + 0xa2, 0x31, 0x1e, 0xcc, 0x4a, 0x0f, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x77, 0x3e, 0xe2, 0x6e, + 0xcd, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2190,6 +2196,16 @@ func (m *MsgAddToConcentratedLiquiditySuperfluidPositionResponse) MarshalToSized _ = i var l int _ = l + { + size := m.NewLiquidity.Size() + i -= size + if _, err := m.NewLiquidity.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if m.LockId != 0 { i = encodeVarintTx(dAtA, i, uint64(m.LockId)) i-- @@ -2528,6 +2544,8 @@ func (m *MsgAddToConcentratedLiquiditySuperfluidPositionResponse) Size() (n int) if m.LockId != 0 { n += 1 + sovTx(uint64(m.LockId)) } + l = m.NewLiquidity.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -4579,6 +4597,40 @@ func (m *MsgAddToConcentratedLiquiditySuperfluidPositionResponse) Unmarshal(dAtA break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewLiquidity", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NewLiquidity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:])