diff --git a/CHANGELOG.md b/CHANGELOG.md index 93d31a98ce1..c0ccda6d4e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### State Breaking +<<<<<<< HEAD ### Bug Fixes +======= +* [#5983](https://github.com/osmosis-labs/osmosis/pull/5983) refactor(CL): 6 return values in CL CreatePosition with a struct +* [#6004](https://github.com/osmosis-labs/osmosis/pull/6004) reduce number of returns for creating full range position +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) ### Misc Improvements * [#5976](https://github.com/osmosis-labs/osmosis/pull/5976) chore[e2e]: faster epoch diff --git a/app/apptesting/concentrated_liquidity.go b/app/apptesting/concentrated_liquidity.go index 72de6f80f35..ef287570b45 100644 --- a/app/apptesting/concentrated_liquidity.go +++ b/app/apptesting/concentrated_liquidity.go @@ -72,11 +72,11 @@ func (s *KeeperTestHelper) PrepareConcentratedPoolWithCoinsAndLockedFullRangePos clPool := s.PrepareCustomConcentratedPool(s.TestAccs[0], denom1, denom2, DefaultTickSpacing, sdk.ZeroDec()) fundCoins := sdk.NewCoins(sdk.NewCoin(denom1, DefaultCoinAmount), sdk.NewCoin(denom2, DefaultCoinAmount)) 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) + positionData, 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.GetConcentratedPoolById(s.Ctx, clPool.GetId()) s.Require().NoError(err) - return clPool, concentratedLockId, positionId + return clPool, concentratedLockId, positionData.ID } // PrepareCustomConcentratedPool sets up a concentrated liquidity pool with the custom parameters. @@ -113,9 +113,9 @@ func (s *KeeperTestHelper) PrepareMultipleConcentratedPools(poolsToCreate uint16 // CreateFullRangePosition creates a full range position and returns position id and the liquidity created. func (s *KeeperTestHelper) CreateFullRangePosition(pool types.ConcentratedPoolExtension, coins sdk.Coins) (uint64, sdk.Dec) { s.FundAcc(s.TestAccs[0], coins) - positionId, _, _, liquidity, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, pool.GetId(), s.TestAccs[0], coins) + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, pool.GetId(), s.TestAccs[0], coins) s.Require().NoError(err) - return positionId, liquidity + return positionData.ID, positionData.Liquidity } // WithdrawFullRangePosition withdraws given liquidity from a position specified by id. diff --git a/app/upgrades/v16/upgrades.go b/app/upgrades/v16/upgrades.go index 65fa1b769c6..d2db4cc3f94 100644 --- a/app/upgrades/v16/upgrades.go +++ b/app/upgrades/v16/upgrades.go @@ -148,7 +148,7 @@ func CreateUpgradeHandler( // Create a full range position via the community pool with the funds that were swapped. fullRangeOsmoDaiCoins := sdk.NewCoins(respectiveOsmo, oneDai) - _, actualOsmoAmtUsed, actualDaiAmtUsed, _, err := keepers.ConcentratedLiquidityKeeper.CreateFullRangePosition(ctx, clPoolId, communityPoolAddress, fullRangeOsmoDaiCoins) + positionData, err := keepers.ConcentratedLiquidityKeeper.CreateFullRangePosition(ctx, clPoolId, communityPoolAddress, fullRangeOsmoDaiCoins) if err != nil { return nil, err } @@ -157,7 +157,7 @@ func CreateUpgradeHandler( // Remove coins we used from the community pool to make the CL position feePool := keepers.DistrKeeper.GetFeePool(ctx) - fulllRangeOsmoDaiCoinsUsed := sdk.NewCoins(sdk.NewCoin(DesiredDenom0, actualOsmoAmtUsed), sdk.NewCoin(DAIIBCDenom, actualDaiAmtUsed)) + fulllRangeOsmoDaiCoinsUsed := sdk.NewCoins(sdk.NewCoin(DesiredDenom0, positionData.Amount0), sdk.NewCoin(DAIIBCDenom, positionData.Amount1)) newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoinsFromCoins(fulllRangeOsmoDaiCoinsUsed...)) if negative { return nil, fmt.Errorf("community pool cannot be negative: %s", newPool) diff --git a/app/upgrades/v17/upgrades.go b/app/upgrades/v17/upgrades.go new file mode 100644 index 00000000000..cf3da1d437d --- /dev/null +++ b/app/upgrades/v17/upgrades.go @@ -0,0 +1,182 @@ +package v17 + +import ( + "fmt" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + + cltypes "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" + gammmigration "github.com/osmosis-labs/osmosis/v17/x/gamm/types/migration" + superfluidtypes "github.com/osmosis-labs/osmosis/v17/x/superfluid/types" + + "github.com/osmosis-labs/osmosis/v17/app/keepers" + "github.com/osmosis-labs/osmosis/v17/app/upgrades" + "github.com/osmosis-labs/osmosis/v17/x/protorev/types" + + poolmanagertypes "github.com/osmosis-labs/osmosis/v17/x/poolmanager/types" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + bpm upgrades.BaseAppParamManager, + keepers *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // Run migrations before applying any other state changes. + // NOTE: DO NOT PUT ANY STATE CHANGES BEFORE RunMigrations(). + migrations, err := mm.RunMigrations(ctx, configurator, fromVM) + if err != nil { + return nil, err + } + + // get all the existing CL pools + pools, err := keepers.ConcentratedLiquidityKeeper.GetPools(ctx) + if err != nil { + return nil, err + } + + // migrate twap records for CL Pools + err = FlipTwapSpotPriceRecords(ctx, pools, keepers) + if err != nil { + return nil, err + } + + // Get community pool address. + communityPoolAddress := keepers.AccountKeeper.GetModuleAddress(distrtypes.ModuleName) + + // fullRangeCoinsUsed tracks the coins we use in the below for loop from the community pool to create the full range position for each new pool. + fullRangeCoinsUsed := sdk.NewCoins() + + poolLinks := []gammmigration.BalancerToConcentratedPoolLink{} + + assetPairs := InitializeAssetPairs(ctx, keepers) + + for _, assetPair := range assetPairs { + // Create a concentrated liquidity pool for asset pair. + clPool, err := keepers.GAMMKeeper.CreateConcentratedPoolFromCFMM(ctx, assetPair.LinkedClassicPool, assetPair.BaseAsset, assetPair.SpreadFactor, TickSpacing) + if err != nil { + return nil, err + } + clPoolId := clPool.GetId() + clPoolDenom := cltypes.GetConcentratedLockupDenomFromPoolId(clPoolId) + + // Add the pool link to the list of pool links (we set them all at once later) + poolLinks = append(poolLinks, gammmigration.BalancerToConcentratedPoolLink{ + BalancerPoolId: assetPair.LinkedClassicPool, + ClPoolId: clPoolId, + }) + + // Determine the amount of baseAsset that can be bought with 1 OSMO. + oneOsmo := sdk.NewCoin(QuoteAsset, sdk.NewInt(1000000)) + linkedClassicPool, err := keepers.PoolManagerKeeper.GetPool(ctx, assetPair.LinkedClassicPool) + if err != nil { + return nil, err + } + respectiveBaseAsset, err := keepers.GAMMKeeper.CalcOutAmtGivenIn(ctx, linkedClassicPool, oneOsmo, assetPair.BaseAsset, sdk.ZeroDec()) + if err != nil { + return nil, err + } + + // Create a full range position via the community pool with the funds we calculated above. + fullRangeCoins := sdk.NewCoins(respectiveBaseAsset, oneOsmo) + positionData, err := keepers.ConcentratedLiquidityKeeper.CreateFullRangePosition(ctx, clPoolId, communityPoolAddress, fullRangeCoins) + if err != nil { + return nil, err + } + + // Track the coins used to create the full range position (we manually update the fee pool later all at once). + fullRangeCoinsUsed = fullRangeCoinsUsed.Add(sdk.NewCoins(sdk.NewCoin(QuoteAsset, positionData.Amount1), sdk.NewCoin(assetPair.BaseAsset, positionData.Amount0))...) + + // If pair was previously superfluid enabled, add the cl pool's full range denom as an authorized superfluid asset. + if assetPair.Superfluid { + superfluidAsset := superfluidtypes.SuperfluidAsset{ + Denom: clPoolDenom, + AssetType: superfluidtypes.SuperfluidAssetTypeConcentratedShare, + } + err = keepers.SuperfluidKeeper.AddNewSuperfluidAsset(ctx, superfluidAsset) + if err != nil { + return nil, err + } + } + + clPoolTwapRecords, err := keepers.TwapKeeper.GetAllMostRecentRecordsForPool(ctx, clPoolId) + if err != nil { + return nil, err + } + + for _, twapRecord := range clPoolTwapRecords { + twapRecord.LastErrorTime = time.Time{} + keepers.TwapKeeper.StoreNewRecord(ctx, twapRecord) + } + } + + // Set the migration links in x/gamm. + // This will also migrate the CFMM distribution records to point to the new CL pools. + err = keepers.GAMMKeeper.UpdateMigrationRecords(ctx, poolLinks) + if err != nil { + return nil, err + } + + // Because we had done direct sends from the community pool, we need to manually change the fee pool to reflect the change in balance. + + // Remove coins we used from the community pool to make the CL positions + feePool := keepers.DistrKeeper.GetFeePool(ctx) + newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoinsFromCoins(fullRangeCoinsUsed...)) + if negative { + return nil, fmt.Errorf("community pool cannot be negative: %s", newPool) + } + + // Update and set the new fee pool + feePool.CommunityPool = newPool + keepers.DistrKeeper.SetFeePool(ctx, feePool) + + // Reset the pool weights upon upgrade. This will add support for CW pools on ProtoRev. + keepers.ProtoRevKeeper.SetInfoByPoolType(ctx, types.DefaultPoolTypeInfo) + + return migrations, nil + } +} + +// FlipTwapSpotPriceRecords flips the denoms and spot price of twap record of a given pool. +func FlipTwapSpotPriceRecords(ctx sdk.Context, pools []poolmanagertypes.PoolI, keepers *keepers.AppKeepers) error { + for _, pool := range pools { + poolId := pool.GetId() + twapRecordHistoricalPoolIndexed, err := keepers.TwapKeeper.GetAllHistoricalPoolIndexedTWAPsForPoolId(ctx, poolId) + if err != nil { + return err + } + + for _, historicalTwapRecord := range twapRecordHistoricalPoolIndexed { + oldRecord := historicalTwapRecord + historicalTwapRecord.Asset0Denom, historicalTwapRecord.Asset1Denom = oldRecord.Asset1Denom, oldRecord.Asset0Denom + historicalTwapRecord.P0LastSpotPrice, historicalTwapRecord.P1LastSpotPrice = oldRecord.P1LastSpotPrice, oldRecord.P0LastSpotPrice + + keepers.TwapKeeper.StoreHistoricalTWAP(ctx, historicalTwapRecord) + keepers.TwapKeeper.DeleteHistoricalRecord(ctx, oldRecord) + } + + clPoolTwapRecords, err := keepers.TwapKeeper.GetAllMostRecentRecordsForPool(ctx, poolId) + if err != nil { + return err + } + + for _, twapRecord := range clPoolTwapRecords { + twapRecord.LastErrorTime = time.Time{} + oldRecord := twapRecord + + twapRecord.Asset0Denom, twapRecord.Asset1Denom = oldRecord.Asset1Denom, oldRecord.Asset0Denom + twapRecord.P0LastSpotPrice, twapRecord.P1LastSpotPrice = oldRecord.P1LastSpotPrice, oldRecord.P0LastSpotPrice + + keepers.TwapKeeper.StoreNewRecord(ctx, twapRecord) + keepers.TwapKeeper.DeleteMostRecentRecord(ctx, oldRecord) + } + } + + return nil +} diff --git a/x/concentrated-liquidity/lp_test.go b/x/concentrated-liquidity/lp_test.go index eba4db093ee..b0b3b0d0e69 100644 --- a/x/concentrated-liquidity/lp_test.go +++ b/x/concentrated-liquidity/lp_test.go @@ -9,10 +9,18 @@ import ( "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" +<<<<<<< HEAD cl "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity" "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/model" clmodel "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/model" types "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/types" +======= + cl "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity" + "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/model" + clmodel "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/model" + cltypes "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" + types "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) ) type lpTest struct { @@ -381,20 +389,36 @@ const ( ) func (s *KeeperTestSuite) createPositionWithLockState(ls lockState, poolId uint64, owner sdk.AccAddress, providedCoins sdk.Coins, dur time.Duration) (uint64, sdk.Dec) { +<<<<<<< HEAD var liquidityCreated sdk.Dec var positionId uint64 var err error +======= + var ( + positionData cl.CreatePositionData + fullRangePositionData cltypes.CreateFullRangePositionData + err error + ) + +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) if ls == locked { - positionId, _, _, liquidityCreated, _, err = s.clk.CreateFullRangePositionLocked(s.Ctx, poolId, owner, providedCoins, dur) + fullRangePositionData, _, err = s.clk.CreateFullRangePositionLocked(s.Ctx, poolId, owner, providedCoins, dur) } else if ls == unlocking { - positionId, _, _, liquidityCreated, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, poolId, owner, providedCoins, dur+time.Hour) + fullRangePositionData, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, poolId, owner, providedCoins, dur+time.Hour) } else if ls == unlocked { - positionId, _, _, liquidityCreated, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, poolId, owner, providedCoins, dur-time.Hour) + fullRangePositionData, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, poolId, owner, providedCoins, dur-time.Hour) } else { +<<<<<<< HEAD positionId, _, _, liquidityCreated, _, _, err = s.clk.CreatePosition(s.Ctx, poolId, owner, providedCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick) +======= + positionData, err = s.clk.CreatePosition(s.Ctx, poolId, owner, providedCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick) + s.Require().NoError(err) + return positionData.ID, positionData.Liquidity +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) } + // full range case s.Require().NoError(err) - return positionId, liquidityCreated + return fullRangePositionData.ID, fullRangePositionData.Liquidity } func (s *KeeperTestSuite) TestWithdrawPosition() { @@ -1952,8 +1976,8 @@ func (s *KeeperTestSuite) TestIsLockMature() { s.Run(name, func() { tc := tc var ( - positionId uint64 concentratedLockId uint64 + positionData types.CreateFullRangePositionData err error ) s.SetupTest() @@ -1965,17 +1989,15 @@ func (s *KeeperTestSuite) TestIsLockMature() { s.FundAcc(s.TestAccs[0], coinsToFund) if tc.unlockingPosition { - positionId, _, _, _, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund, tc.remainingLockDuration) - s.Require().NoError(err) + positionData, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund, tc.remainingLockDuration) } else if tc.lockedPosition { - positionId, _, _, _, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund, tc.remainingLockDuration) - s.Require().NoError(err) + positionData, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund, tc.remainingLockDuration) } else { - positionId, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund) - s.Require().NoError(err) + positionData, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, pool.GetId(), s.TestAccs[0], coinsToFund) } + s.Require().NoError(err) - _, err = s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionId) + _, err = s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionData.ID) s.Require().NoError(err) // Increment block time by a second to ensure test cases with zero lock duration are in the past @@ -1984,11 +2006,7 @@ func (s *KeeperTestSuite) TestIsLockMature() { // System under test lockIsMature, _ := s.App.ConcentratedLiquidityKeeper.IsLockMature(s.Ctx, concentratedLockId) - if tc.expectedLockIsMature { - s.Require().True(lockIsMature) - } else { - s.Require().False(lockIsMature) - } + s.Require().Equal(tc.expectedLockIsMature, lockIsMature) }) } } diff --git a/x/concentrated-liquidity/pool_test.go b/x/concentrated-liquidity/pool_test.go index b3e748425e4..19528d6d018 100644 --- a/x/concentrated-liquidity/pool_test.go +++ b/x/concentrated-liquidity/pool_test.go @@ -682,7 +682,7 @@ func (s *KeeperTestSuite) TestGetUserUnbondingPositions() { // Create 3 locked positions for i := 0; i < 3; i++ { - _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, defaultFunds, time.Hour) + _, _, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, defaultFunds, time.Hour) s.Require().NoError(err) } diff --git a/x/concentrated-liquidity/position.go b/x/concentrated-liquidity/position.go index b0c26ae0b05..152da5570be 100644 --- a/x/concentrated-liquidity/position.go +++ b/x/concentrated-liquidity/position.go @@ -393,78 +393,82 @@ 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, poolId uint64, owner sdk.AccAddress, coins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, err error) { +func (k Keeper) CreateFullRangePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, coins sdk.Coins) (types.CreateFullRangePositionData, error) { // Check that exactly two coins are provided. if len(coins) != 2 { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, types.NumCoinsError{NumCoins: len(coins)} + return types.CreateFullRangePositionData{}, types.NumCoinsError{NumCoins: len(coins)} } concentratedPool, err := k.GetConcentratedPoolById(ctx, poolId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, err + return types.CreateFullRangePositionData{}, err } // Defense in depth, ensure coins provided match the pool's token denominations. if coins.AmountOf(concentratedPool.GetToken0()).LTE(sdk.ZeroInt()) { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, types.Amount0IsNegativeError{Amount0: coins.AmountOf(concentratedPool.GetToken0())} + return types.CreateFullRangePositionData{}, types.Amount0IsNegativeError{Amount0: coins.AmountOf(concentratedPool.GetToken0())} } if coins.AmountOf(concentratedPool.GetToken1()).LTE(sdk.ZeroInt()) { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, types.Amount1IsNegativeError{Amount1: coins.AmountOf(concentratedPool.GetToken1())} + return types.CreateFullRangePositionData{}, types.Amount1IsNegativeError{Amount1: coins.AmountOf(concentratedPool.GetToken1())} } // Create a full range (min to max tick) concentrated liquidity position. positionId, amount0, amount1, liquidity, _, _, err = k.createPosition(ctx, concentratedPool.GetId(), owner, coins, sdk.ZeroInt(), sdk.ZeroInt(), types.MinInitializedTick, types.MaxTick) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, err + return types.CreateFullRangePositionData{}, err } +<<<<<<< HEAD return positionId, amount0, amount1, liquidity, nil +======= + return types.CreateFullRangePositionData{ID: positionData.ID, Amount0: positionData.Amount0, Amount1: positionData.Amount1, Liquidity: positionData.Liquidity}, nil +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) } // CreateFullRangePositionLocked creates a full range (min to max tick) concentrated liquidity position for the given pool ID, owner, and coins. // CL shares are minted which represent the underlying liquidity and are locked for the given duration. // State entries are also created to map the position ID to the underlying lock ID. -func (k Keeper) CreateFullRangePositionLocked(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockID uint64, err error) { +func (k Keeper) CreateFullRangePositionLocked(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionData types.CreateFullRangePositionData, concentratedLockID uint64, err error) { // Create a full range (min to max tick) concentrated liquidity position. - positionId, amount0, amount1, liquidity, err = k.CreateFullRangePosition(ctx, clPoolId, owner, coins) + positionData, err = k.CreateFullRangePosition(ctx, clPoolId, owner, coins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return types.CreateFullRangePositionData{}, 0, err } // Mint CL shares (similar to GAMM 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.mintSharesAndLock(ctx, clPoolId, positionId, owner, remainingLockDuration) + concentratedLockId, _, err := k.mintSharesAndLock(ctx, clPoolId, positionData.ID, owner, remainingLockDuration) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return types.CreateFullRangePositionData{}, 0, err } - return positionId, amount0, amount1, liquidity, concentratedLockId, nil + return positionData, concentratedLockId, nil } // CreateFullRangePositionUnlocking creates a full range (min to max tick) concentrated liquidity position for the given pool ID, owner, and coins. // This function is strictly used when migrating a balancer position to CL, where the balancer position is currently unlocking. // We lock the cl position for whatever the remaining time is from the balancer position and immediately begin unlocking from where it left off. -func (k Keeper) CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockID uint64, err error) { +func (k Keeper) CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionData types.CreateFullRangePositionData, concentratedLockID uint64, err error) { // Create a full range (min to max tick) concentrated liquidity position. - positionId, amount0, amount1, liquidity, err = k.CreateFullRangePosition(ctx, clPoolId, owner, coins) + positionData, err = k.CreateFullRangePosition(ctx, clPoolId, owner, coins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return types.CreateFullRangePositionData{}, 0, err } // 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.mintSharesAndLock(ctx, clPoolId, positionId, owner, remainingLockDuration) + concentratedLockId, underlyingLiquidityTokenized, err := k.mintSharesAndLock(ctx, clPoolId, positionData.ID, owner, remainingLockDuration) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return types.CreateFullRangePositionData{}, 0, err } // Begin unlocking the newly created concentrated lock. concentratedLockID, err = k.lockupKeeper.BeginForceUnlock(ctx, concentratedLockId, underlyingLiquidityTokenized) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return types.CreateFullRangePositionData{}, 0, err } - return positionId, amount0, amount1, liquidity, concentratedLockID, nil + return positionData, concentratedLockID, nil } // 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. diff --git a/x/concentrated-liquidity/position_test.go b/x/concentrated-liquidity/position_test.go index d989cf26312..6f395946a76 100644 --- a/x/concentrated-liquidity/position_test.go +++ b/x/concentrated-liquidity/position_test.go @@ -9,12 +9,21 @@ import ( "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/osmoutils/accum" +<<<<<<< HEAD "github.com/osmosis-labs/osmosis/osmoutils/osmoassert" "github.com/osmosis-labs/osmosis/v16/app/apptesting" cl "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity" "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/math" "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/model" "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/types" +======= + "github.com/osmosis-labs/osmosis/v17/app/apptesting" + cl "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity" + "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/math" + "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/model" + "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" + cltypes "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) ) const ( @@ -1031,12 +1040,20 @@ func (s *KeeperTestSuite) TestValidateAndFungifyChargedPositions() { lockDuration := testFullChargeDuration + testFullChargeDuration + test.unlockBeforeBlockTimeMs for _, pos := range test.setupFullyChargedPositions { var ( +<<<<<<< HEAD liquidityCreated sdk.Dec err error +======= + liquidityCreated sdk.Dec + err error + positionData cl.CreatePositionData + fullRangePositionData cltypes.CreateFullRangePositionData +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) ) if pos.isLocked { - _, _, _, liquidityCreated, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, pos.poolId, pos.acc, pos.coins, lockDuration) + fullRangePositionData, _, err = s.clk.CreateFullRangePositionUnlocking(s.Ctx, pos.poolId, pos.acc, pos.coins, lockDuration) s.Require().NoError(err) + liquidityCreated = fullRangePositionData.Liquidity } else { _, _, _, liquidityCreated, _, _, err = s.clk.CreatePosition(s.Ctx, pos.poolId, pos.acc, pos.coins, sdk.ZeroInt(), sdk.ZeroInt(), pos.lowerTick, pos.upperTick) s.Require().NoError(err) @@ -1587,8 +1604,7 @@ func (s *KeeperTestSuite) TestFunctionalFungifyChargedPositions() { func (s *KeeperTestSuite) TestCreateFullRangePosition() { var ( - positionId uint64 - liquidity sdk.Dec + positionData cltypes.CreateFullRangePositionData concentratedLockId uint64 err error ) @@ -1669,11 +1685,11 @@ func (s *KeeperTestSuite) TestCreateFullRangePosition() { // System under test if test.isLocked { - positionId, _, _, liquidity, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) + positionData, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) } else if test.isUnlocking { - positionId, _, _, liquidity, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) + positionData, concentratedLockId, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) } else { - positionId, _, _, liquidity, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition) + positionData, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition) } if test.expectedErr != nil { @@ -1685,14 +1701,14 @@ func (s *KeeperTestSuite) TestCreateFullRangePosition() { s.Require().NoError(err) // Check position - _, err = s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionId) + _, err = s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionData.ID) s.Require().NoError(err) // Check lock if test.isLocked || test.isUnlocking { concentratedLock, err := s.App.LockupKeeper.GetLockByID(s.Ctx, concentratedLockId) s.Require().NoError(err) - s.Require().Equal(liquidity.TruncateInt().String(), concentratedLock.Coins[0].Amount.String()) + s.Require().Equal(positionData.Liquidity.TruncateInt().String(), concentratedLock.Coins[0].Amount.String()) isUnlocking := concentratedLock.IsUnlocking() s.Require().Equal(!test.isLocked, isUnlocking) } @@ -1765,8 +1781,10 @@ func (s *KeeperTestSuite) TestMintSharesAndLock() { liquidity := sdk.ZeroDec() if test.createFullRangePosition { var err error - positionId, _, _, liquidity, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), test.owner, DefaultCoins) + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), test.owner, DefaultCoins) s.Require().NoError(err) + positionId = positionData.ID + liquidity = positionData.Liquidity } else { var err error positionId, _, _, liquidity, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, clPool.GetId(), test.owner, defaultPositionCoins, sdk.ZeroInt(), sdk.ZeroInt(), test.lowerTick, test.upperTick) @@ -1833,10 +1851,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLock() { name: "position with lock locked", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked( + positionData, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked( s.Ctx, clPool.GetId(), owner, defaultPositionCoins, defaultLockDuration) s.Require().NoError(err) - return positionID, concentratedLockID + return positionData.ID, concentratedLockID }, expectedHasActiveLock: true, // lock starts as active expectedHasActiveLockAfterTimeUpdate: true, // since lock is locked, it remains active after time update @@ -1848,10 +1866,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLock() { name: "position with lock unlocking", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking( + positionData, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking( s.Ctx, clPool.GetId(), owner, defaultPositionCoins, defaultLockDuration) s.Require().NoError(err) - return positionID, concentratedLockID + return positionData.ID, concentratedLockID }, expectedHasActiveLock: true, // lock starts as active expectedHasActiveLockAfterTimeUpdate: false, // since lock is unlocking, it should no longer be active after time update @@ -1863,10 +1881,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLock() { name: "position without lock", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition( + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition( s.Ctx, clPool.GetId(), owner, defaultPositionCoins) s.Require().NoError(err) - return positionID, 0 + return positionData.ID, 0 }, expectedHasActiveLock: false, expectedHasActiveLockAfterTimeUpdate: false, @@ -1960,10 +1978,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLockAndUpdate() { name: "position with lock locked", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked( + positionData, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked( s.Ctx, clPool.GetId(), owner, defaultPositionCoins, defaultLockDuration) s.Require().NoError(err) - return positionID, concentratedLockID + return positionData.ID, concentratedLockID }, expectedHasActiveLock: true, // lock starts as active expectedHasActiveLockAfterTimeUpdate: true, // since lock is locked, it remains active after time update @@ -1977,10 +1995,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLockAndUpdate() { name: "position with lock unlocking", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking( + positionData, concentratedLockID, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking( s.Ctx, clPool.GetId(), owner, defaultPositionCoins, defaultLockDuration) s.Require().NoError(err) - return positionID, concentratedLockID + return positionData.ID, concentratedLockID }, expectedHasActiveLock: true, // lock starts as active expectedHasActiveLockAfterTimeUpdate: false, // since lock is unlocking, it should no longer be active after time update @@ -1994,10 +2012,10 @@ func (s *KeeperTestSuite) TestPositionHasActiveUnderlyingLockAndUpdate() { name: "position without lock", createPosition: func(s *KeeperTestSuite) (uint64, uint64) { s.FundAcc(owner, defaultPositionCoins) - positionID, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition( + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition( s.Ctx, clPool.GetId(), owner, defaultPositionCoins) s.Require().NoError(err) - return positionID, 0 + return positionData.ID, 0 }, expectedHasActiveLock: false, expectedHasActiveLockAfterTimeUpdate: false, @@ -2091,46 +2109,46 @@ func (s *KeeperTestSuite) TestPositionToLockCRUD() { s.FundAcc(owner, defaultPositionCoins) // Create a position with a lock - positionId, _, _, _, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, clPool.GetId(), owner, defaultPositionCoins, remainingLockDuration) + positionData, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, clPool.GetId(), owner, defaultPositionCoins, remainingLockDuration) s.Require().NoError(err) // We should be able to retrieve the lockId from the positionId now - retrievedLockId, err := s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionId) + retrievedLockId, err := s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionData.ID) s.Require().NoError(err) s.Require().Equal(concentratedLockId, retrievedLockId) // Check if lock has position in state retrievedPositionId, err := s.App.ConcentratedLiquidityKeeper.GetPositionIdToLockId(s.Ctx, retrievedLockId) s.Require().NoError(err) - s.Require().Equal(positionId, retrievedPositionId) + s.Require().Equal(positionData.ID, retrievedPositionId) // Create a position without a lock - positionId, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), owner, defaultPositionCoins) + positionData, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), owner, defaultPositionCoins) s.Require().Error(err) // Check if position has lock in state, should not - retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionId) + retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionData.ID) s.Require().Error(err) s.Require().Equal(uint64(0), retrievedLockId) // Set the position to have a lockId (despite it not actually having a lock) - s.App.ConcentratedLiquidityKeeper.SetPositionIdToLock(s.Ctx, positionId, concentratedLockId) + s.App.ConcentratedLiquidityKeeper.SetPositionIdToLock(s.Ctx, positionData.ID, concentratedLockId) // Check if position has lock in state, it should now - retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionId) + retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionData.ID) s.Require().NoError(err) s.Require().Equal(concentratedLockId, retrievedLockId) // Check if lock has position in state retrievedPositionId, err = s.App.ConcentratedLiquidityKeeper.GetPositionIdToLockId(s.Ctx, retrievedLockId) s.Require().NoError(err) - s.Require().Equal(positionId, retrievedPositionId) + s.Require().Equal(positionData.ID, retrievedPositionId) // Remove the lockId from the position - s.App.ConcentratedLiquidityKeeper.RemovePositionIdForLockId(s.Ctx, positionId, retrievedLockId) + s.App.ConcentratedLiquidityKeeper.RemovePositionIdForLockId(s.Ctx, positionData.ID, retrievedLockId) // Check if position has lock in state, should not - retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionId) + retrievedLockId, err = s.App.ConcentratedLiquidityKeeper.GetLockIdFromPositionId(s.Ctx, positionData.ID) s.Require().Error(err) s.Require().Equal(uint64(0), retrievedLockId) } @@ -2263,9 +2281,9 @@ func (s *KeeperTestSuite) TestGetAndUpdateFullRangeLiquidity() { actualFullRangeLiquidity := sdk.ZeroDec() // Create a full range position. - _, _, _, liquidity, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), owner, tc.positionCoins) + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPool.GetId(), owner, tc.positionCoins) s.Require().NoError(err) - actualFullRangeLiquidity = actualFullRangeLiquidity.Add(liquidity) + actualFullRangeLiquidity = actualFullRangeLiquidity.Add(positionData.Liquidity) clPool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, clPoolId) s.Require().NoError(err) @@ -2382,7 +2400,7 @@ func (s *KeeperTestSuite) TestCreateFullRangePositionLocked() { s.FundAcc(defaultAddress, test.coinsForPosition) // System under test - positionId, _, _, liquidity, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) + positionData, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPool.GetId(), defaultAddress, test.coinsForPosition, test.remainingLockDuration) if test.expectedErr != nil { s.Require().ErrorContains(err, test.expectedErr.Error()) @@ -2392,18 +2410,18 @@ func (s *KeeperTestSuite) TestCreateFullRangePositionLocked() { s.Require().NoError(err) // Check position - position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionId) + position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionData.ID) s.Require().NoError(err) s.Require().Equal(s.Ctx.BlockTime(), position.JoinTime) s.Require().Equal(types.MaxTick, position.UpperTick) s.Require().Equal(types.MinInitializedTick, position.LowerTick) - s.Require().Equal(liquidity, position.Liquidity) + s.Require().Equal(positionData.Liquidity, position.Liquidity) // Check locked concentratedLock, err := s.App.LockupKeeper.GetLockByID(s.Ctx, concentratedLockId) s.Require().NoError(err) - s.Require().Equal(concentratedLock.Coins[0].Amount.String(), liquidity.TruncateInt().String()) + s.Require().Equal(concentratedLock.Coins[0].Amount.String(), positionData.Liquidity.TruncateInt().String()) s.Require().False(concentratedLock.IsUnlocking()) }) } diff --git a/x/concentrated-liquidity/swaps_tick_cross_test.go b/x/concentrated-liquidity/swaps_tick_cross_test.go index ee3a517a418..7528a34df58 100644 --- a/x/concentrated-liquidity/swaps_tick_cross_test.go +++ b/x/concentrated-liquidity/swaps_tick_cross_test.go @@ -162,7 +162,7 @@ func (s *KeeperTestSuite) setupPoolAndPositions(testTickSpacing uint64, position // Create a full range position s.FundAcc(s.TestAccs[0], DefaultCoins) - _, _, _, liquidityFullRange, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, poolId, s.TestAccs[0], initialCoins) + positionData, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, poolId, s.TestAccs[0], initialCoins) s.Require().NoError(err) // Refetch pool as the first position updated its state. @@ -172,7 +172,7 @@ func (s *KeeperTestSuite) setupPoolAndPositions(testTickSpacing uint64, position // Create all narrow range positions per given tick spacings away from the current tick // configuration. positionMetas := make([]positionMeta, len(positionTickSpacingsFromCurrTick)) - liquidityAllPositions := liquidityFullRange + liquidityAllPositions := positionData.Liquidity for i, tickSpacingsAway := range positionTickSpacingsFromCurrTick { // Create narrow range position tickSpacingsAway from the current tick positionMetas[i] = s.CreatePositionTickSpacingsFromCurrentTick(poolId, tickSpacingsAway) diff --git a/x/concentrated-liquidity/types/cl.go b/x/concentrated-liquidity/types/cl.go index 5e345f298e8..9fc2bc8d4df 100644 --- a/x/concentrated-liquidity/types/cl.go +++ b/x/concentrated-liquidity/types/cl.go @@ -2,9 +2,21 @@ package types import ( fmt "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // GetConcentratedLockupDenomFromPoolId returns the concentrated lockup denom for a given pool id. func GetConcentratedLockupDenomFromPoolId(poolId uint64) string { return fmt.Sprintf("%s/%d", ConcentratedLiquidityTokenPrefix, poolId) } + +// CreateFullRangePositionData represents the return data from any method +// that creates a full range position. We have multipl variants to +// account for varying locking scenarios. +type CreateFullRangePositionData struct { + ID uint64 + Amount0 sdk.Int + Amount1 sdk.Int + Liquidity sdk.Dec +} diff --git a/x/gamm/keeper/migrate.go b/x/gamm/keeper/migrate.go index 48547c139f3..8c5a71e96e0 100644 --- a/x/gamm/keeper/migrate.go +++ b/x/gamm/keeper/migrate.go @@ -19,41 +19,41 @@ import ( func (k Keeper) MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins, -) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, poolIdLeaving, poolIdEntering uint64, err error) { +) (positionData cltypes.CreateFullRangePositionData, poolIdLeaving, poolIdEntering uint64, err error) { // Get the balancer poolId by parsing the gamm share denom. poolIdLeaving, err = types.GetPoolIdFromShareDenom(sharesToMigrate.Denom) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, err } // Find the governance sanctioned link between the balancer pool and a concentrated pool. poolIdEntering, err = k.GetLinkedConcentratedPoolID(ctx, poolIdLeaving) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, err } // Get the concentrated pool from the message and type cast it to ConcentratedPoolExtension. concentratedPool, err := k.concentratedLiquidityKeeper.GetConcentratedPoolById(ctx, poolIdEntering) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, err } // Exit the balancer pool position. exitCoins, err := k.ExitPool(ctx, sender, poolIdLeaving, sharesToMigrate.Amount, tokenOutMins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, err } // Defense in depth, ensuring we are returning exactly two coins. if len(exitCoins) != 2 { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, fmt.Errorf("Balancer pool must have exactly two tokens") + return cltypes.CreateFullRangePositionData{}, 0, 0, fmt.Errorf("Balancer pool must have exactly two tokens") } // Create a full range (min to max tick) concentrated liquidity position. - positionId, amount0, amount1, liquidity, err = k.concentratedLiquidityKeeper.CreateFullRangePosition(ctx, concentratedPool.GetId(), sender, exitCoins) + positionData, err = k.concentratedLiquidityKeeper.CreateFullRangePosition(ctx, concentratedPool.GetId(), sender, exitCoins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, err } - return positionId, amount0, amount1, liquidity, poolIdLeaving, poolIdEntering, nil + return positionData, poolIdLeaving, poolIdEntering, nil } // GetAllMigrationInfo gets all existing links between Balancer Pool and Concentrated Pool, diff --git a/x/gamm/keeper/migrate_test.go b/x/gamm/keeper/migrate_test.go index 6241708d3b6..d2b0412129a 100644 --- a/x/gamm/keeper/migrate_test.go +++ b/x/gamm/keeper/migrate_test.go @@ -212,7 +212,7 @@ func (s *KeeperTestSuite) TestMigrate() { // Migrate the user's gamm shares to a full range concentrated liquidity position userBalancesBeforeMigration := s.App.BankKeeper.GetAllBalances(s.Ctx, test.param.sender) - positionId, amount0, amount1, _, poolIdLeaving, poolIdEntering, err := keeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, test.param.sender, sharesToMigrate, test.tokenOutMins) + positionData, poolIdLeaving, poolIdEntering, err := keeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, test.param.sender, sharesToMigrate, test.tokenOutMins) userBalancesAfterMigration := s.App.BankKeeper.GetAllBalances(s.Ctx, test.param.sender) if test.expectedErr != nil { s.Require().Error(err) @@ -234,7 +234,7 @@ func (s *KeeperTestSuite) TestMigrate() { // Assure the position was not created. // TODO: When we implement lock breaking, we need to change time.Time{} to the lock's end time. - _, err := s.App.ConcentratedLiquidityKeeper.GetPositionLiquidity(s.Ctx, positionId) + _, err := s.App.ConcentratedLiquidityKeeper.GetPositionLiquidity(s.Ctx, positionData.ID) s.Require().Error(err) continue } @@ -247,14 +247,14 @@ func (s *KeeperTestSuite) TestMigrate() { // Determine how much of the user's balance was not used in the migration // This amount should be returned to the user. - expectedUserFinalEthBalanceDiff := expectedCoinsOut.AmountOf(ETH).Sub(amount0) - expectedUserFinalUsdcBalanceDiff := expectedCoinsOut.AmountOf(USDC).Sub(amount1) + expectedUserFinalEthBalanceDiff := expectedCoinsOut.AmountOf(ETH).Sub(positionData.Amount0) + expectedUserFinalUsdcBalanceDiff := expectedCoinsOut.AmountOf(USDC).Sub(positionData.Amount1) s.Require().Equal(userBalancesBeforeMigration.AmountOf(ETH).Add(expectedUserFinalEthBalanceDiff).String(), userBalancesAfterMigration.AmountOf(ETH).String()) s.Require().Equal(userBalancesBeforeMigration.AmountOf(USDC).Add(expectedUserFinalUsdcBalanceDiff).String(), userBalancesAfterMigration.AmountOf(USDC).String()) // Assure the expected position was created. // TODO: When we implement lock breaking, we need to change time.Time{} to the lock's end time. - position, err := s.App.ConcentratedLiquidityKeeper.GetPositionLiquidity(s.Ctx, positionId) + position, err := s.App.ConcentratedLiquidityKeeper.GetPositionLiquidity(s.Ctx, positionData.ID) s.Require().NoError(err) s.Require().Equal(test.expectedLiquidity, position) @@ -277,8 +277,8 @@ func (s *KeeperTestSuite) TestMigrate() { // Assert user amount transferred to cl pool from gamm pool should be equal to the amount we migrated from the migrate message. // This test is within 100 shares due to rounding that occurs from utilizing .000000000000000001 instead of 0. - s.Require().Equal(0, test.errTolerance.Compare(userEthBalanceTransferredToClPool.Amount, amount0)) - s.Require().Equal(0, test.errTolerance.Compare(userUsdcBalanceTransferredToClPool.Amount, amount1)) + s.Require().Equal(0, test.errTolerance.Compare(userEthBalanceTransferredToClPool.Amount, positionData.Amount0)) + s.Require().Equal(0, test.errTolerance.Compare(userUsdcBalanceTransferredToClPool.Amount, positionData.Amount0)) } } diff --git a/x/gamm/types/expected_keepers.go b/x/gamm/types/expected_keepers.go index cd7351ed9ae..aded45c9f6d 100644 --- a/x/gamm/types/expected_keepers.go +++ b/x/gamm/types/expected_keepers.go @@ -53,7 +53,7 @@ type CommunityPoolKeeper interface { // ConcentratedLiquidityKeeper defines the contract needed to be fulfilled for the concentrated liquidity keeper. type ConcentratedLiquidityKeeper interface { 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, err error) + CreateFullRangePosition(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, err error) } // PoolManager defines the interface needed to be fulfilled for diff --git a/x/lockup/keeper/lock_test.go b/x/lockup/keeper/lock_test.go index ed1287a5d23..ce34d46c156 100644 --- a/x/lockup/keeper/lock_test.go +++ b/x/lockup/keeper/lock_test.go @@ -1310,7 +1310,7 @@ func (s *KeeperTestSuite) TestSlashTokensFromLockByIDSendUnderlyingAndBurn() { // Create a cl pool and a locked full range position clPool := s.PrepareConcentratedPool() clPoolId := clPool.GetId() - positionID, _, _, liquidity, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, addr, tc.positionCoins, time.Hour) + positionData, concentratedLockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, addr, tc.positionCoins, time.Hour) s.Require().NoError(err) // Refetch the cl pool post full range position creation @@ -1321,7 +1321,7 @@ func (s *KeeperTestSuite) TestSlashTokensFromLockByIDSendUnderlyingAndBurn() { // Check the supply of the cl asset before we slash it is equal to the liquidity created clAssetSupplyPreSlash := s.App.BankKeeper.GetSupply(s.Ctx, clPoolPositionDenom) - s.Require().Equal(liquidity.TruncateInt().String(), clAssetSupplyPreSlash.Amount.String()) + s.Require().Equal(positionData.Liquidity.TruncateInt().String(), clAssetSupplyPreSlash.Amount.String()) // Store the cl pool balance before the slash clPoolBalancePreSlash := s.App.BankKeeper.GetAllBalances(s.Ctx, clPool.GetAddress()) @@ -1331,15 +1331,15 @@ func (s *KeeperTestSuite) TestSlashTokensFromLockByIDSendUnderlyingAndBurn() { Denom: clPoolPositionDenom, Duration: time.Second, }) - s.Require().Equal(liquidity.TruncateInt64(), acc.Int64()) + s.Require().Equal(positionData.Liquidity.TruncateInt64(), acc.Int64()) // The lockup module account balance before the slash should match the liquidity added to the lock lockupModuleBalancePreSlash := s.App.LockupKeeper.GetModuleBalance(s.Ctx) - s.Require().Equal(sdk.NewCoins(sdk.NewCoin(clPoolPositionDenom, liquidity.TruncateInt())), lockupModuleBalancePreSlash) + s.Require().Equal(sdk.NewCoins(sdk.NewCoin(clPoolPositionDenom, positionData.Liquidity.TruncateInt())), lockupModuleBalancePreSlash) // Slash the cl shares and the underlying assets // Figure out the underlying assets from the liquidity slash - position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionID) + position, err := s.App.ConcentratedLiquidityKeeper.GetPosition(s.Ctx, positionData.ID) s.Require().NoError(err) concentratedPool, err := s.App.ConcentratedLiquidityKeeper.GetConcentratedPoolById(s.Ctx, position.PoolId) diff --git a/x/superfluid/keeper/concentrated_liquidity.go b/x/superfluid/keeper/concentrated_liquidity.go index 56454d75bf7..2b094e5950c 100644 --- a/x/superfluid/keeper/concentrated_liquidity.go +++ b/x/superfluid/keeper/concentrated_liquidity.go @@ -29,33 +29,33 @@ import ( // - The position is not superfluid staked. // - The position is the last position in the pool. // - 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) { +func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, sender sdk.AccAddress, positionId uint64, amount0ToAdd, amount1ToAdd sdk.Int) (cltypes.CreateFullRangePositionData, uint64, error) { position, err := k.clk.GetPosition(ctx, positionId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } if amount0ToAdd.IsNegative() || amount1ToAdd.IsNegative() { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, cltypes.NegativeAmountAddedError{PositionId: position.PositionId, Asset0Amount: amount0ToAdd, Asset1Amount: amount1ToAdd} + return cltypes.CreateFullRangePositionData{}, 0, cltypes.NegativeAmountAddedError{PositionId: position.PositionId, Asset0Amount: amount0ToAdd, Asset1Amount: amount1ToAdd} } // If the position is not superfluid staked, return error. positionHasActiveUnderlyingLock, lockId, err := k.clk.PositionHasActiveUnderlyingLock(ctx, positionId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } if !positionHasActiveUnderlyingLock || lockId == 0 { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.PositionNotSuperfluidStakedError{PositionId: position.PositionId} + return cltypes.CreateFullRangePositionData{}, 0, types.PositionNotSuperfluidStakedError{PositionId: position.PositionId} } // Defense in depth making sure that the position is full-range. if position.LowerTick != cltypes.MinInitializedTick || position.UpperTick != cltypes.MaxTick { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.ConcentratedTickRangeNotFullError{ActualLowerTick: position.LowerTick, ActualUpperTick: position.UpperTick} + return cltypes.CreateFullRangePositionData{}, 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 + return cltypes.CreateFullRangePositionData{}, 0, err } // Defense in depth. Require the underlying lock: @@ -64,60 +64,60 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, se // - duration is equal to unbonding time // - end time is zero (not unbonding) if lock.Owner != position.Address { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: position.Address} + return cltypes.CreateFullRangePositionData{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: position.Address} } if lock.Owner != sender.String() { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: sender.String()} + return cltypes.CreateFullRangePositionData{}, 0, types.LockOwnerMismatchError{LockId: lockId, LockOwner: lock.Owner, ProvidedOwner: sender.String()} } unbondingDuration := k.sk.UnbondingTime(ctx) if lock.Duration != unbondingDuration || !lock.EndTime.IsZero() { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, types.LockImproperStateError{LockId: lockId, UnbondingDuration: unbondingDuration.String()} + return cltypes.CreateFullRangePositionData{}, 0, types.LockImproperStateError{LockId: lockId, UnbondingDuration: unbondingDuration.String()} } // 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, sender.String(), lockId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } // Finish unlocking directly for the lock. // This also breaks and deletes associated synthetic locks. err = k.lk.ForceUnlock(ctx, *lock) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } // 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 + return cltypes.CreateFullRangePositionData{}, 0, err } // If this is the last position in the pool, error. anyPositionsRemainingInPool, err := k.clk.HasAnyPositionForPool(ctx, position.PoolId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } if !anyPositionsRemainingInPool { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, cltypes.AddToLastPositionInPoolError{PoolId: position.PoolId, PositionId: position.PositionId} + return cltypes.CreateFullRangePositionData{}, 0, cltypes.AddToLastPositionInPoolError{PoolId: position.PoolId, PositionId: position.PositionId} } // Create a coins object that includes the old position coins and the new position coins. concentratedPool, err := k.clk.GetConcentratedPoolById(ctx, position.PoolId) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 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, actualNewAmount0, actualNewAmount1, newLiquidity, newLockId, err := k.clk.CreateFullRangePositionLocked(ctx, position.PoolId, sender, newPositionCoins, unbondingDuration) + positionData, newLockId, err := k.clk.CreateFullRangePositionLocked(ctx, position.PoolId, sender, newPositionCoins, unbondingDuration) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } err = k.SuperfluidDelegate(ctx, sender.String(), newLockId, intermediateAccount.ValAddr) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err + return cltypes.CreateFullRangePositionData{}, 0, err } // Emit events. @@ -130,13 +130,13 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, se types.TypeEvtAddToConcentratedLiquiditySuperfluidPosition, sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), sdk.NewAttribute(types.AttributePositionId, strconv.FormatUint(positionId, 10)), - sdk.NewAttribute(types.AttributeNewPositionId, strconv.FormatUint(newPositionId, 10)), - sdk.NewAttribute(types.AttributeAmount0, actualNewAmount0.String()), - sdk.NewAttribute(types.AttributeAmount1, actualNewAmount1.String()), + sdk.NewAttribute(types.AttributeNewPositionId, strconv.FormatUint(positionData.ID, 10)), + sdk.NewAttribute(types.AttributeAmount0, positionData.Amount0.String()), + sdk.NewAttribute(types.AttributeAmount1, positionData.Amount1.String()), sdk.NewAttribute(types.AttributeConcentratedLockId, strconv.FormatUint(newLockId, 10)), - sdk.NewAttribute(types.AttributeLiquidity, newLiquidity.String()), + sdk.NewAttribute(types.AttributeLiquidity, positionData.Liquidity.String()), ), }) - return newPositionId, actualNewAmount0, actualNewAmount1, newLiquidity, newLockId, nil + return positionData, newLockId, nil } diff --git a/x/superfluid/keeper/concentrated_liquidity_test.go b/x/superfluid/keeper/concentrated_liquidity_test.go index d49acdd8328..8f574e9dc46 100644 --- a/x/superfluid/keeper/concentrated_liquidity_test.go +++ b/x/superfluid/keeper/concentrated_liquidity_test.go @@ -135,7 +135,7 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() { if !tc.isLastPositionInPool { fundCoins := sdk.NewCoins(sdk.NewCoin(clPool.GetToken0(), sdk.NewInt(100000000)), sdk.NewCoin(clPool.GetToken1(), sdk.NewInt(100000000))) s.FundAcc(nonOwner, fundCoins) - _, _, _, _, err := concentratedLiquidityKeeper.CreateFullRangePosition(ctx, clPool.GetId(), nonOwner, fundCoins) + _, err := concentratedLiquidityKeeper.CreateFullRangePosition(ctx, clPool.GetId(), nonOwner, fundCoins) s.Require().NoError(err) } @@ -147,7 +147,7 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() { preAddToPositionPoolFunds := bankKeeper.GetAllBalances(ctx, clPoolAddress) // System under test. - newPositionId, finalAmount0, finalAmount1, newLiquidity, newLockId, err := superfluidKeeper.AddToConcentratedLiquiditySuperfluidPosition(ctx, executionAcc, positionId, tc.amount0Added, tc.amount1Added) + positionData, newLockId, err := superfluidKeeper.AddToConcentratedLiquiditySuperfluidPosition(ctx, executionAcc, positionId, tc.amount0Added, tc.amount1Added) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorContains(err, tc.expectedError.Error()) @@ -184,11 +184,11 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() { expectedNewCoins := sdk.NewCoins(sdk.NewCoin(clPool.GetToken0(), amount0.Add(tc.amount0Added)), sdk.NewCoin(clPool.GetToken1(), amount1.Add(tc.amount1Added))) clPoolDenom := cltypes.GetConcentratedLockupDenomFromPoolId(clPool.GetId()) - expectedLockCoins := sdk.NewCoins(sdk.NewCoin(clPoolDenom, newLiquidity.TruncateInt())) + expectedLockCoins := sdk.NewCoins(sdk.NewCoin(clPoolDenom, positionData.Liquidity.TruncateInt())) // Resulting position should have the expected amount of coins within one unit (rounding down). - s.Require().Equal(0, errTolerance.Compare(expectedNewCoins[0].Amount, finalAmount0), fmt.Sprintf("expected (%s), actual (%s)", expectedNewCoins[0].Amount, finalAmount0)) - s.Require().Equal(0, errTolerance.Compare(expectedNewCoins[1].Amount, finalAmount1), fmt.Sprintf("expected (%s), actual (%s)", expectedNewCoins[1].Amount, finalAmount1)) + s.Require().Equal(0, errTolerance.Compare(expectedNewCoins[0].Amount, positionData.Amount0), fmt.Sprintf("expected (%s), actual (%s)", expectedNewCoins[0].Amount, positionData.Amount0)) + s.Require().Equal(0, errTolerance.Compare(expectedNewCoins[1].Amount, positionData.Amount1), fmt.Sprintf("expected (%s), actual (%s)", expectedNewCoins[1].Amount, positionData.Amount1)) // Check the new lock. newLock, err := s.App.LockupKeeper.GetLockByID(ctx, newLockId) @@ -199,7 +199,7 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() { s.Require().Equal(expectedLockCoins.String(), newLock.Coins.String()) // Check that a new position and lock ID were generated. - s.Require().NotEqual(positionId, newPositionId) + s.Require().NotEqual(positionId, positionData.ID) s.Require().NotEqual(lockId, newLockId) // Check if intermediary account connection for the old lock ID is deleted. @@ -224,7 +224,7 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition() { s.Require().False(found) // Check if the new intermediary account has expected delegation amount. - expectedDelegationAmt := superfluidKeeper.GetRiskAdjustedOsmoValue(ctx, finalAmount0) + expectedDelegationAmt := superfluidKeeper.GetRiskAdjustedOsmoValue(ctx, positionData.Amount0) delegationAmt, found := stakingKeeper.GetDelegation(ctx, newIntermediaryAcc, valAddr) s.Require().True(found) s.Require().Equal(expectedDelegationAmt, delegationAmt.Shares.TruncateInt()) @@ -263,8 +263,11 @@ func (s *KeeperTestSuite) SetupSuperfluidConcentratedPosition(ctx sdk.Context, s unbondingDuration := stakingKeeper.GetParams(ctx).UnbondingTime // Create a full range position in the concentrated liquidity pool. - positionId, amount0, amount1, _, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, poolJoinAcc, fullRangeCoins, unbondingDuration) + positionData, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, poolJoinAcc, fullRangeCoins, unbondingDuration) s.Require().NoError(err) + positionId = positionData.ID + amount0 = positionData.Amount0 + amount1 = positionData.Amount1 // Register the CL full range LP tokens as a superfluid asset. clPoolDenom := cltypes.GetConcentratedLockupDenomFromPoolId(clPoolId) diff --git a/x/superfluid/keeper/export_test.go b/x/superfluid/keeper/export_test.go index 7c30ff05c7c..8374457dc6d 100644 --- a/x/superfluid/keeper/export_test.go +++ b/x/superfluid/keeper/export_test.go @@ -5,8 +5,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" +<<<<<<< HEAD lockuptypes "github.com/osmosis-labs/osmosis/v16/x/lockup/types" "github.com/osmosis-labs/osmosis/v16/x/superfluid/types" +======= + cltypes "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" + lockuptypes "github.com/osmosis-labs/osmosis/v17/x/lockup/types" +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) ) var ( @@ -22,15 +27,15 @@ func (k Keeper) PrepareConcentratedLockForSlash(ctx sdk.Context, lock *lockuptyp return k.prepareConcentratedLockForSlash(ctx, lock, slashAmt) } -func (k Keeper) MigrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +func (k Keeper) MigrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { return k.migrateSuperfluidBondedBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthDenomBeforeMigration, tokenOutMins) } -func (k Keeper) MigrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +func (k Keeper) MigrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { return k.migrateSuperfluidUnbondingBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthDenomBeforeMigration, tokenOutMins) } -func (k Keeper) MigrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +func (k Keeper) MigrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { return k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) } @@ -46,7 +51,7 @@ func (k Keeper) ValidateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId return k.validateMigration(ctx, sender, lockId, sharesToMigrate) } -func (k Keeper) AddToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, amount0Added, amount1Added sdk.Int) (uint64, sdk.Int, sdk.Int, sdk.Dec, uint64, error) { +func (k Keeper) AddToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, amount0Added, amount1Added sdk.Int) (cltypes.CreateFullRangePositionData, uint64, error) { return k.addToConcentratedLiquiditySuperfluidPosition(ctx, owner, positionId, amount0Added, amount1Added) } diff --git a/x/superfluid/keeper/grpc_query_test.go b/x/superfluid/keeper/grpc_query_test.go index 0a6c8543e4b..959654a12c1 100644 --- a/x/superfluid/keeper/grpc_query_test.go +++ b/x/superfluid/keeper/grpc_query_test.go @@ -313,7 +313,7 @@ func (s *KeeperTestSuite) TestUserConcentratedSuperfluidPositionsBondedAndUnbond expectedBondedLockIds := []uint64{} expectedBondedTotalSharesLocked := sdk.Coins{} for i := 0; i < 4; i++ { - posId, _, _, _, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, s.TestAccs[0], coins, duration) + positionData, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId, s.TestAccs[0], coins, duration) s.Require().NoError(err) lock, err := s.App.LockupKeeper.GetLockByID(s.Ctx, lockId) @@ -322,13 +322,13 @@ func (s *KeeperTestSuite) TestUserConcentratedSuperfluidPositionsBondedAndUnbond err = s.App.SuperfluidKeeper.SuperfluidDelegate(s.Ctx, lock.Owner, lock.ID, valAddrs[0].String()) s.Require().NoError(err) - expectedBondedPositionIds = append(expectedBondedPositionIds, posId) + expectedBondedPositionIds = append(expectedBondedPositionIds, positionData.ID) expectedBondedLockIds = append(expectedBondedLockIds, lockId) expectedBondedTotalSharesLocked = expectedBondedTotalSharesLocked.Add(lock.Coins[0]) } // Create 1 position in pool 1 that is not superfluid delegated. - _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPoolId, s.TestAccs[0], coins) + _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPoolId, s.TestAccs[0], coins) s.Require().NoError(err) // Create 4 positions in pool 2 that are superfluid undelegating. @@ -336,7 +336,7 @@ func (s *KeeperTestSuite) TestUserConcentratedSuperfluidPositionsBondedAndUnbond expectedUnbondingLockIds := []uint64{} expectedUnbondingTotalSharesLocked := sdk.Coins{} for i := 0; i < 4; i++ { - posId, _, _, _, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId2, s.TestAccs[0], coins, duration) + positionData, lockId, err := s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionLocked(s.Ctx, clPoolId2, s.TestAccs[0], coins, duration) s.Require().NoError(err) lock, err := s.App.LockupKeeper.GetLockByID(s.Ctx, lockId) @@ -348,13 +348,13 @@ func (s *KeeperTestSuite) TestUserConcentratedSuperfluidPositionsBondedAndUnbond _, err = s.App.SuperfluidKeeper.SuperfluidUndelegateAndUnbondLock(s.Ctx, lockId, lock.Owner, lock.Coins[0].Amount) s.Require().NoError(err) - expectedUnbondingPositionIds = append(expectedUnbondingPositionIds, posId) + expectedUnbondingPositionIds = append(expectedUnbondingPositionIds, positionData.ID) expectedUnbondingLockIds = append(expectedUnbondingLockIds, lockId) expectedUnbondingTotalSharesLocked = expectedUnbondingTotalSharesLocked.Add(lock.Coins[0]) } // Create 1 position in pool 2 that is not superfluid delegated. - _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPoolId2, s.TestAccs[0], coins) + _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, clPoolId2, s.TestAccs[0], coins) s.Require().NoError(err) // Query the bonded positions. diff --git a/x/superfluid/keeper/migrate.go b/x/superfluid/keeper/migrate.go index 47257b4bfa6..3b7a1993a84 100644 --- a/x/superfluid/keeper/migrate.go +++ b/x/superfluid/keeper/migrate.go @@ -42,10 +42,10 @@ const ( // - Create new CL lock and starts unlocking or unlocking where it left off. // // Errors if the lock is not found, if the lock is not a balancer pool lock, or if the lock is not owned by the sender. -func (k Keeper) RouteLockedBalancerToConcentratedMigration(ctx sdk.Context, sender sdk.AccAddress, providedLockId int64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, poolIdLeaving, poolIdEntering, concentratedLockId uint64, err error) { +func (k Keeper) RouteLockedBalancerToConcentratedMigration(ctx sdk.Context, sender sdk.AccAddress, providedLockId int64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, poolIdLeaving, poolIdEntering, concentratedLockId uint64, err error) { synthLockBeforeMigration, migrationType, err := k.routeMigration(ctx, sender, providedLockId, sharesToMigrate) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // As a hack around to get frontend working, we decided to allow negative values for the provided lock ID to indicate that the user wants to migrate shares that are not locked. @@ -53,19 +53,19 @@ func (k Keeper) RouteLockedBalancerToConcentratedMigration(ctx sdk.Context, send switch migrationType { case SuperfluidBonded: - positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidBondedBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidBondedBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) case SuperfluidUnbonding: - positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidUnbondingBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidUnbondingBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) case NonSuperfluid: - positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) case Unlocked: - positionId, amount0, amount1, liquidity, poolIdLeaving, poolIdEntering, err = k.gk.MigrateUnlockedPositionFromBalancerToConcentrated(ctx, sender, sharesToMigrate, tokenOutMins) + positionData, poolIdLeaving, poolIdEntering, err = k.gk.MigrateUnlockedPositionFromBalancerToConcentrated(ctx, sender, sharesToMigrate, tokenOutMins) concentratedLockId = 0 default: - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, fmt.Errorf("unsupported migration type") + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, fmt.Errorf("unsupported migration type") } - return positionId, amount0, amount1, liquidity, poolIdLeaving, poolIdEntering, concentratedLockId, err + return positionData, poolIdLeaving, poolIdEntering, concentratedLockId, err } // migrateSuperfluidBondedBalancerToConcentrated migrates a user's superfluid bonded balancer position to a superfluid bonded concentrated liquidity position. @@ -78,10 +78,10 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins, -) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, originalLockId, sharesToMigrate) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } isPartialMigration := sharesToMigrate.Amount.LT(preMigrationLock.Coins[0].Amount) @@ -90,12 +90,13 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, valAddr := strings.Split(synthDenomBeforeMigration, "/")[4] _, err = sdk.ValAddressFromBech32(valAddr) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Superfluid undelegate the portion of shares the user is migrating from the superfluid delegated position. // If all shares are being migrated, this deletes the connection between the gamm lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo. intermediateAccount := types.SuperfluidIntermediaryAccount{} +<<<<<<< HEAD var gammLockToMigrate *lockuptypes.PeriodLock if isPartialMigration { // Note that lock's id is different from the originalLockId since it was split. @@ -112,6 +113,12 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, if err != nil { return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err } +======= + + intermediateAccount, err = k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), originalLockId) + if err != nil { + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err +>>>>>>> 07c85560 (refactor: reduce number of returns for creating full range position (#6004)) } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. @@ -119,21 +126,21 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, // It also returns the lock object that contains the remaining shares that were not used in this migration. exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, gammLockToMigrate, sharesToMigrate, tokenOutMins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Create a full range (min to max tick) concentrated liquidity position, lock it, and superfluid delegate it. - positionId, amount0, amount1, liquidity, concentratedLockId, err = k.clk.CreateFullRangePositionLocked(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err = k.clk.CreateFullRangePositionLocked(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } err = k.SuperfluidDelegate(ctx, sender.String(), concentratedLockId, intermediateAccount.ValAddr) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } - return positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil } // migrateSuperfluidUnbondingBalancerToConcentrated migrates a user's superfluid unbonding balancer position to a superfluid unbonding concentrated liquidity position. @@ -147,17 +154,17 @@ func (k Keeper) migrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins, -) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Get the validator address from the synth denom and ensure it is a valid address. valAddr := strings.Split(synthDenomBeforeMigration, "/")[4] _, err = sdk.ValAddressFromBech32(valAddr) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. @@ -165,13 +172,13 @@ func (k Keeper) migrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context // It also returns the lock object that contains the remaining shares that were not used in this migration. exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, preMigrationLock, sharesToMigrate, tokenOutMins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Create a full range (min to max tick) concentrated liquidity position. - positionId, amount0, amount1, liquidity, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // The previous gamm intermediary account is now invalid for the new lock, since the underlying denom has changed and intermediary accounts are @@ -180,17 +187,17 @@ func (k Keeper) migrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context concentratedLockupDenom := cltypes.GetConcentratedLockupDenomFromPoolId(poolIdEntering) clIntermediateAccount, err := k.GetOrCreateIntermediaryAccount(ctx, concentratedLockupDenom, valAddr) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Synthetic lock is created to indicate unbonding position. The synthetic lock will be in unbonding period for remainingLockTime. // Create a new synthetic lockup for the new intermediary account in an unlocking status for the remaining duration. err = k.createSyntheticLockupWithDuration(ctx, concentratedLockId, clIntermediateAccount, remainingLockTime, unlockingStatus) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } - return positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil } // migrateNonSuperfluidLockBalancerToConcentrated migrates a user's non-superfluid locked or unlocking balancer position to an unlocking concentrated liquidity position. @@ -202,10 +209,10 @@ func (k Keeper) migrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, lockId uint64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins, -) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. @@ -213,18 +220,18 @@ func (k Keeper) migrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, // It also returns the lock object that contains the remaining shares that were not used in this migration. exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, preMigrationLock, sharesToMigrate, tokenOutMins) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } // Create a new lock that is unlocking for the remaining time of the old lock. // Regardless of the previous lock's status, we create a new lock that is unlocking. // This is because locking without superfluid is pointless in the context of concentrated liquidity. - positionId, amount0, amount1, liquidity, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) if err != nil { - return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } - return positionId, amount0, amount1, liquidity, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil } // routeMigration determines the status of the provided lock which is used to determine the method for migration. diff --git a/x/superfluid/keeper/migrate_test.go b/x/superfluid/keeper/migrate_test.go index b4068bd2f6b..45b863ca318 100644 --- a/x/superfluid/keeper/migrate_test.go +++ b/x/superfluid/keeper/migrate_test.go @@ -184,7 +184,7 @@ func (s *KeeperTestSuite) TestRouteLockedBalancerToConcentratedMigration() { balancerDelegationPre, _ := stakingKeeper.GetDelegation(s.Ctx, balancerIntermediaryAcc.GetAccAddress(), valAddr) // Run the migration logic. - positionId, amount0, amount1, liquidityMigrated, poolIdLeaving, poolIdEntering, concentratedLockId, err := superfluidKeeper.RouteLockedBalancerToConcentratedMigration(s.Ctx, poolJoinAcc, int64(originalGammLockId), coinsToMigrate, tc.minExitCoins) + positionData, poolIdLeaving, poolIdEntering, concentratedLockId, err := superfluidKeeper.RouteLockedBalancerToConcentratedMigration(s.Ctx, poolJoinAcc, int64(originalGammLockId), coinsToMigrate, tc.minExitCoins) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorIs(err, tc.expectedError) @@ -194,12 +194,12 @@ func (s *KeeperTestSuite) TestRouteLockedBalancerToConcentratedMigration() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionId, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, - tc.percentOfSharesToMigrate, liquidityMigrated, + positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, balancerPoolShareOut, coinsToMigrate, - amount0, amount1, + positionData.Amount0, positionData.Amount1, ) // If the lock was superfluid delegated: @@ -350,7 +350,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidBondedBalancerToConcentrated() { balancerDelegationPre, _ := stakingKeeper.GetDelegation(s.Ctx, balancerIntermediaryAcc.GetAccAddress(), valAddr) // System under test. - positionId, amount0, amount1, liquidityMigrated, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidBondedBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidBondedBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorContains(err, tc.expectedError.Error()) @@ -360,12 +360,12 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidBondedBalancerToConcentrated() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionId, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, - tc.percentOfSharesToMigrate, liquidityMigrated, + positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, balancerPoolShareOut, coinsToMigrate, - amount0, amount1, + positionData.Amount0, positionData.Amount1, ) if tc.percentOfSharesToMigrate.Equal(sdk.OneDec()) { @@ -421,7 +421,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidBondedBalancerToConcentrated() { concentratedLock, err := lockupKeeper.GetLockByID(s.Ctx, concentratedLockId) s.Require().NoError(err) - s.Require().Equal(liquidityMigrated.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) + s.Require().Equal(positionData.Liquidity.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) s.Require().Equal(balancerLock.Duration, concentratedLock.Duration) s.Require().Equal(balancerLock.EndTime, concentratedLock.EndTime) @@ -505,7 +505,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidUnbondingBalancerToConcentrated() } // System under test. - positionId, amount0, amount1, liquidityMigrated, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidUnbondingBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidUnbondingBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorContains(err, tc.expectedError.Error()) @@ -515,12 +515,12 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidUnbondingBalancerToConcentrated() s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionId, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, - tc.percentOfSharesToMigrate, liquidityMigrated, + positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, balancerPoolShareOut, coinsToMigrate, - amount0, amount1, + positionData.Amount0, positionData.Amount1, ) if tc.percentOfSharesToMigrate.Equal(sdk.OneDec()) { @@ -542,7 +542,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidUnbondingBalancerToConcentrated() // Check newly created concentrated lock. concentratedLock, err := lockupKeeper.GetLockByID(s.Ctx, concentratedLockId) s.Require().NoError(err) - s.Require().Equal(liquidityMigrated.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) + s.Require().Equal(positionData.Liquidity.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) // If the original lock was not unlocking, then the new lock should have the same duration and end time (regardless of the fact that an hour has passed since the lock began superfluid unbonding). expectedConcentratedLockDuration := balancerLock.Duration expectedConcentratedLockEndTime := s.Ctx.BlockTime().Add(balancerLock.Duration) @@ -620,7 +620,7 @@ func (s *KeeperTestSuite) TestMigrateNonSuperfluidLockBalancerToConcentrated() { s.Require().Equal(migrationType, keeper.NonSuperfluid) // System under test. - positionId, amount0, amount1, liquidityMigrated, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateNonSuperfluidLockBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, tc.tokenOutMins) + positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateNonSuperfluidLockBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, tc.tokenOutMins) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorContains(err, tc.expectedError.Error()) @@ -630,18 +630,18 @@ func (s *KeeperTestSuite) TestMigrateNonSuperfluidLockBalancerToConcentrated() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionId, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, - tc.percentOfSharesToMigrate, liquidityMigrated, + positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, balancerPoolShareOut, coinsToMigrate, - amount0, amount1, + positionData.Amount0, positionData.Amount1, ) // Check newly created concentrated lock. concentratedLock, err := lockupKeeper.GetLockByID(s.Ctx, concentratedLockId) s.Require().NoError(err) - s.Require().Equal(liquidityMigrated.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) + s.Require().Equal(positionData.Liquidity.TruncateInt().String(), concentratedLock.Coins[0].Amount.String(), "expected %s shares, found %s shares", coinsToMigrate.Amount.String(), concentratedLock.Coins[0].Amount.String()) s.Require().Equal(balancerLock.Duration, concentratedLock.Duration) s.Require().Equal(s.Ctx.BlockTime().Add(balancerLock.Duration), concentratedLock.EndTime) @@ -703,7 +703,7 @@ func (s *KeeperTestSuite) TestMigrateUnlockedPositionFromBalancerToConcentrated( s.Require().Equal(migrationType, keeper.Unlocked) // System under test. - positionId, amount0, amount1, liquidityMigrated, poolIdLeaving, poolIdEntering, err := gammKeeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, poolJoinAcc, coinsToMigrate, tc.tokenOutMins) + positionData, poolIdLeaving, poolIdEntering, err := gammKeeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, poolJoinAcc, coinsToMigrate, tc.tokenOutMins) if tc.expectedError != nil { s.Require().ErrorContains(err, tc.expectedError.Error()) return @@ -712,12 +712,12 @@ func (s *KeeperTestSuite) TestMigrateUnlockedPositionFromBalancerToConcentrated( s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionId, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, - tc.percentOfSharesToMigrate, liquidityMigrated, + positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, balancerPoolShareOut, coinsToMigrate, - amount0, amount1, + positionData.Amount0, positionData.Amount1, ) }) } @@ -1403,11 +1403,11 @@ func (s *KeeperTestSuite) TestFunctional_VaryingPositions_Migrations() { preClaimBalancerPoolBalance := balancerPool.GetTotalPoolLiquidity(s.Ctx) // Run the migration. - _, amount0, amount1, _, _, _, _, err := s.App.SuperfluidKeeper.RouteLockedBalancerToConcentratedMigration(s.Ctx, s.TestAccs[i+1], int64(posInfo.lockId), posInfo.coin, sdk.Coins{}) + positionData, _, _, _, err := s.App.SuperfluidKeeper.RouteLockedBalancerToConcentratedMigration(s.Ctx, s.TestAccs[i+1], int64(posInfo.lockId), posInfo.coin, sdk.Coins{}) s.Require().NoError(err) // Note how much of amount0 and amount1 was actually created in the CL pool from the migration. - clJoinPoolAmt := sdk.NewCoins(sdk.NewCoin(clPool.GetToken0(), amount0), sdk.NewCoin(clPool.GetToken1(), amount1)) + clJoinPoolAmt := sdk.NewCoins(sdk.NewCoin(clPool.GetToken0(), positionData.Amount0), sdk.NewCoin(clPool.GetToken1(), positionData.Amount1)) // Note owner and balancer pool balances after migration. balancerPool, err = s.App.GAMMKeeper.GetCFMMPool(s.Ctx, balancerPoolId) @@ -1429,8 +1429,8 @@ func (s *KeeperTestSuite) TestFunctional_VaryingPositions_Migrations() { } // Add to the total amounts that were migrated and sent back to the owners. - totalAmount0Migrated = totalAmount0Migrated.Add(amount0) - totalAmount1Migrated = totalAmount1Migrated.Add(amount1) + totalAmount0Migrated = totalAmount0Migrated.Add(positionData.Amount0) + totalAmount1Migrated = totalAmount1Migrated.Add(positionData.Amount1) totalSentBackToOwnersAmount0 = totalSentBackToOwnersAmount0.Add(postClaimOwnerBalance.AmountOf(DefaultCoin0.Denom).Sub(preClaimOwnerBalance.AmountOf(DefaultCoin0.Denom))) totalSentBackToOwnersAmount1 = totalSentBackToOwnersAmount1.Add(postClaimOwnerBalance.AmountOf(DefaultCoin1.Denom).Sub(preClaimOwnerBalance.AmountOf(DefaultCoin1.Denom))) } diff --git a/x/superfluid/keeper/msg_server.go b/x/superfluid/keeper/msg_server.go index 19d94ddabc3..4ab3118202f 100644 --- a/x/superfluid/keeper/msg_server.go +++ b/x/superfluid/keeper/msg_server.go @@ -172,7 +172,7 @@ func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx conte if err != nil { return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err } - positionId, _, _, _, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime) + positionData, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime) if err != nil { return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err } @@ -189,11 +189,11 @@ func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx conte return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err } - events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionId, msg.ValAddr) + events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionData.ID, msg.ValAddr) return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{ LockID: lockId, - PositionID: positionId, + PositionID: positionData.ID, }, nil } @@ -205,7 +205,7 @@ func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(go return nil, err } - positionId, amount0, amount1, liquidity, poolIdLeaving, poolIdEntering, clLockId, err := server.keeper.RouteLockedBalancerToConcentratedMigration(ctx, sender, msg.LockId, msg.SharesToMigrate, msg.TokenOutMins) + positionData, poolIdLeaving, poolIdEntering, clLockId, err := server.keeper.RouteLockedBalancerToConcentratedMigration(ctx, sender, msg.LockId, msg.SharesToMigrate, msg.TokenOutMins) if err != nil { return nil, err } @@ -217,14 +217,14 @@ func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(go sdk.NewAttribute(types.AttributeKeyPoolIdLeaving, strconv.FormatUint(poolIdLeaving, 10)), sdk.NewAttribute(types.AttributeConcentratedLockId, strconv.FormatUint(clLockId, 10)), sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributePositionId, strconv.FormatUint(positionId, 10)), - sdk.NewAttribute(types.AttributeAmount0, amount0.String()), - sdk.NewAttribute(types.AttributeAmount1, amount1.String()), - sdk.NewAttribute(types.AttributeLiquidity, liquidity.String()), + sdk.NewAttribute(types.AttributePositionId, strconv.FormatUint(positionData.ID, 10)), + sdk.NewAttribute(types.AttributeAmount0, positionData.Amount0.String()), + sdk.NewAttribute(types.AttributeAmount1, positionData.Amount1.String()), + sdk.NewAttribute(types.AttributeLiquidity, positionData.Liquidity.String()), ), }) - return &types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse{Amount0: amount0, Amount1: amount1, LiquidityCreated: liquidity}, err + return &types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse{Amount0: positionData.Amount0, Amount1: positionData.Amount1, LiquidityCreated: positionData.Liquidity}, err } func (server msgServer) AddToConcentratedLiquiditySuperfluidPosition(goCtx context.Context, msg *types.MsgAddToConcentratedLiquiditySuperfluidPosition) (*types.MsgAddToConcentratedLiquiditySuperfluidPositionResponse, error) { @@ -235,10 +235,10 @@ func (server msgServer) AddToConcentratedLiquiditySuperfluidPosition(goCtx conte return nil, err } - newPositionId, actualAmount0, actualAmount1, newLiquidity, newLockId, err := server.keeper.addToConcentratedLiquiditySuperfluidPosition(ctx, sender, msg.PositionId, msg.TokenDesired0.Amount, msg.TokenDesired1.Amount) + positionData, 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, NewLiquidity: newLiquidity}, nil + return &types.MsgAddToConcentratedLiquiditySuperfluidPositionResponse{PositionId: positionData.ID, Amount0: positionData.Amount0, Amount1: positionData.Amount1, LockId: newLockId, NewLiquidity: positionData.Liquidity}, nil } diff --git a/x/superfluid/keeper/msg_server_test.go b/x/superfluid/keeper/msg_server_test.go index 4817dc1f691..c6bc6a83c5b 100644 --- a/x/superfluid/keeper/msg_server_test.go +++ b/x/superfluid/keeper/msg_server_test.go @@ -564,7 +564,7 @@ func (s *KeeperTestSuite) TestAddToConcentratedLiquiditySuperfluidPosition_Event if !tc.isLastPositionInPool { s.FundAcc(s.TestAccs[1], defaultFunds) - _, _, _, _, err := concentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, 1, s.TestAccs[1], defaultFunds) + _, err := concentratedLiquidityKeeper.CreateFullRangePosition(s.Ctx, 1, s.TestAccs[1], defaultFunds) s.Require().NoError(err) } diff --git a/x/superfluid/types/expected_keepers.go b/x/superfluid/types/expected_keepers.go index 34106f4db0d..d6c76d612b6 100644 --- a/x/superfluid/types/expected_keepers.go +++ b/x/superfluid/types/expected_keepers.go @@ -56,7 +56,7 @@ type GammKeeper interface { ExitPool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, shareInAmount sdk.Int, tokenOutMins sdk.Coins) (exitCoins sdk.Coins, err error) GetAllMigrationInfo(ctx sdk.Context) (gammmigration.MigrationRecords, error) GetLinkedConcentratedPoolID(ctx sdk.Context, poolIdLeaving uint64) (poolIdEntering uint64, err error) - MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionId uint64, amount0, amount1 sdk.Int, liquidity sdk.Dec, poolIdLeaving, poolIdEntering uint64, err error) + MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, poolIdLeaving, poolIdEntering uint64, err error) } type BankKeeper interface { @@ -111,8 +111,8 @@ type ConcentratedKeeper interface { 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) 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, 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, concentratedLockID uint64, err error) + CreateFullRangePositionLocked(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionData cltypes.CreateFullRangePositionData, concentratedLockID uint64, err error) + CreateFullRangePositionUnlocking(ctx sdk.Context, clPoolId uint64, owner sdk.AccAddress, coins sdk.Coins, remainingLockDuration time.Duration) (positionData cltypes.CreateFullRangePositionData, concentratedLockID uint64, err error) GetPositionIdToLockId(ctx sdk.Context, underlyingLockId uint64) (uint64, error) GetFullRangeLiquidityInPool(ctx sdk.Context, poolId uint64) (sdk.Dec, error) PositionHasActiveUnderlyingLock(ctx sdk.Context, positionId uint64) (bool, uint64, error)