From b94dc8c8749671badd6181c016b4490cfdff72d3 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 10 Aug 2023 20:09:59 +0200 Subject: [PATCH] refactor: reduce the number of returns in superfluid migration (#6014) * refactor: reduce the number of returns in superfluid migration * changelog (cherry picked from commit 7a92e7823952ef51cc7ec114cba6f25f8f2ad2e9) # Conflicts: # x/gamm/keeper/migrate.go # x/superfluid/keeper/export_test.go # x/superfluid/keeper/migrate.go --- CHANGELOG.md | 1 + x/gamm/keeper/migrate.go | 34 +++++--- x/gamm/keeper/migrate_test.go | 10 +-- x/superfluid/keeper/export_test.go | 14 +++- x/superfluid/keeper/migrate.go | 110 ++++++++++++++----------- x/superfluid/keeper/migrate_test.go | 30 +++---- x/superfluid/keeper/msg_server.go | 6 +- x/superfluid/types/expected_keepers.go | 2 +- x/superfluid/types/migration.go | 6 ++ 9 files changed, 126 insertions(+), 87 deletions(-) create mode 100644 x/superfluid/types/migration.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 238ad6635b7..255062d05f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### API breaks +* [#6014](https://github.com/osmosis-labs/osmosis/pull/6014) refactor: reduce the number of returns in superfluid migration * [#5983](https://github.com/osmosis-labs/osmosis/pull/5983) refactor(CL): 6 return values in CL CreatePosition with a struct * [#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 diff --git a/x/gamm/keeper/migrate.go b/x/gamm/keeper/migrate.go index 8c5a71e96e0..41cac4286e6 100644 --- a/x/gamm/keeper/migrate.go +++ b/x/gamm/keeper/migrate.go @@ -5,10 +5,19 @@ import ( "sort" "github.com/osmosis-labs/osmosis/osmoutils" +<<<<<<< HEAD cltypes "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/types" "github.com/osmosis-labs/osmosis/v16/x/gamm/types" gammmigration "github.com/osmosis-labs/osmosis/v16/x/gamm/types/migration" poolmanagertypes "github.com/osmosis-labs/osmosis/v16/x/poolmanager/types" +======= + clmodel "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/model" + cltypes "github.com/osmosis-labs/osmosis/v17/x/concentrated-liquidity/types" + "github.com/osmosis-labs/osmosis/v17/x/gamm/types" + gammmigration "github.com/osmosis-labs/osmosis/v17/x/gamm/types/migration" + poolmanagertypes "github.com/osmosis-labs/osmosis/v17/x/poolmanager/types" + superfluidtypes "github.com/osmosis-labs/osmosis/v17/x/superfluid/types" +>>>>>>> 7a92e782 (refactor: reduce the number of returns in superfluid migration (#6014)) "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,41 +28,44 @@ import ( func (k Keeper) MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins, -) (positionData cltypes.CreateFullRangePositionData, poolIdLeaving, poolIdEntering uint64, err error) { +) (cltypes.CreateFullRangePositionData, superfluidtypes.MigrationPoolIDs, error) { // Get the balancer poolId by parsing the gamm share denom. - poolIdLeaving, err = types.GetPoolIdFromShareDenom(sharesToMigrate.Denom) + poolIdLeaving, err := types.GetPoolIdFromShareDenom(sharesToMigrate.Denom) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, err } // Find the governance sanctioned link between the balancer pool and a concentrated pool. - poolIdEntering, err = k.GetLinkedConcentratedPoolID(ctx, poolIdLeaving) + poolIdEntering, err := k.GetLinkedConcentratedPoolID(ctx, poolIdLeaving) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, 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 cltypes.CreateFullRangePositionData{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, err } // Exit the balancer pool position. exitCoins, err := k.ExitPool(ctx, sender, poolIdLeaving, sharesToMigrate.Amount, tokenOutMins) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, err } // Defense in depth, ensuring we are returning exactly two coins. if len(exitCoins) != 2 { - return cltypes.CreateFullRangePositionData{}, 0, 0, fmt.Errorf("Balancer pool must have exactly two tokens") + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, fmt.Errorf("Balancer pool must have exactly two tokens") } // Create a full range (min to max tick) concentrated liquidity position. - positionData, err = k.concentratedLiquidityKeeper.CreateFullRangePosition(ctx, concentratedPool.GetId(), sender, exitCoins) + positionData, err := k.concentratedLiquidityKeeper.CreateFullRangePosition(ctx, concentratedPool.GetId(), sender, exitCoins) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, err + return cltypes.CreateFullRangePositionData{}, superfluidtypes.MigrationPoolIDs{}, err } - return positionData, poolIdLeaving, poolIdEntering, nil + return positionData, superfluidtypes.MigrationPoolIDs{ + LeavingID: poolIdLeaving, + EnteringID: 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 d2b0412129a..7d3f9201acf 100644 --- a/x/gamm/keeper/migrate_test.go +++ b/x/gamm/keeper/migrate_test.go @@ -212,15 +212,15 @@ 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) - positionData, poolIdLeaving, poolIdEntering, err := keeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, test.param.sender, sharesToMigrate, test.tokenOutMins) + positionData, migratedPools, 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) s.Require().ErrorContains(err, test.expectedErr.Error()) // Expect zero values for both pool ids - s.Require().Zero(poolIdLeaving) - s.Require().Zero(poolIdEntering) + s.Require().Zero(migratedPools.LeavingID) + s.Require().Zero(migratedPools.EnteringID) // Assure the user's gamm shares still exist userGammBalanceAfterFailedMigration := s.App.BankKeeper.GetBalance(s.Ctx, test.param.sender, "gamm/pool/1") @@ -242,8 +242,8 @@ func (s *KeeperTestSuite) TestMigrate() { // Expect the poolIdLeaving to be the balancer pool id // Expect the poolIdEntering to be the concentrated liquidity pool id - s.Require().Equal(balancerPoolId, poolIdLeaving) - s.Require().Equal(clPool.GetId(), poolIdEntering) + s.Require().Equal(balancerPoolId, migratedPools.LeavingID) + s.Require().Equal(clPool.GetId(), migratedPools.EnteringID) // Determine how much of the user's balance was not used in the migration // This amount should be returned to the user. diff --git a/x/superfluid/keeper/export_test.go b/x/superfluid/keeper/export_test.go index 9baa09412aa..7ebb5500d10 100644 --- a/x/superfluid/keeper/export_test.go +++ b/x/superfluid/keeper/export_test.go @@ -5,9 +5,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" +<<<<<<< HEAD cltypes "github.com/osmosis-labs/osmosis/v16/x/concentrated-liquidity/types" 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" + types "github.com/osmosis-labs/osmosis/v17/x/superfluid/types" +>>>>>>> 7a92e782 (refactor: reduce the number of returns in superfluid migration (#6014)) ) var ( @@ -23,15 +29,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) (positionData cltypes.CreateFullRangePositionData, 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) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, 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) (positionData cltypes.CreateFullRangePositionData, 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) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, 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) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { +func (k Keeper) MigrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, error) { return k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) } @@ -43,7 +49,7 @@ func (k Keeper) RouteMigration(ctx sdk.Context, sender sdk.AccAddress, lockId in return k.routeMigration(ctx, sender, lockId, sharesToMigrate) } -func (k Keeper) ValidateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin) (poolIdLeaving, poolIdEntering uint64, preMigrationLock *lockuptypes.PeriodLock, remainingLockTime time.Duration, err error) { +func (k Keeper) ValidateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin) (types.MigrationPoolIDs, *lockuptypes.PeriodLock, time.Duration, error) { return k.validateMigration(ctx, sender, lockId, sharesToMigrate) } diff --git a/x/superfluid/keeper/migrate.go b/x/superfluid/keeper/migrate.go index c64ef1413b5..f07fa2f3172 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) (positionData cltypes.CreateFullRangePositionData, 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, migratedPoolIDs types.MigrationPoolIDs, concentratedLockId uint64, err error) { synthLockBeforeMigration, migrationType, err := k.routeMigration(ctx, sender, providedLockId, sharesToMigrate) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, types.MigrationPoolIDs{}, 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: - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidBondedBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) + positionData, concentratedLockId, migratedPoolIDs, err = k.migrateSuperfluidBondedBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) case SuperfluidUnbonding: - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateSuperfluidUnbondingBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) + positionData, concentratedLockId, migratedPoolIDs, err = k.migrateSuperfluidUnbondingBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, synthLockBeforeMigration.SynthDenom, tokenOutMins) case NonSuperfluid: - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err = k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) + positionData, concentratedLockId, migratedPoolIDs, err = k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins) case Unlocked: - positionData, poolIdLeaving, poolIdEntering, err = k.gk.MigrateUnlockedPositionFromBalancerToConcentrated(ctx, sender, sharesToMigrate, tokenOutMins) + positionData, migratedPoolIDs, err = k.gk.MigrateUnlockedPositionFromBalancerToConcentrated(ctx, sender, sharesToMigrate, tokenOutMins) concentratedLockId = 0 default: - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, fmt.Errorf("unsupported migration type") + return cltypes.CreateFullRangePositionData{}, types.MigrationPoolIDs{}, 0, fmt.Errorf("unsupported migration type") } - return positionData, poolIdLeaving, poolIdEntering, concentratedLockId, err + return positionData, migratedPoolIDs, 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, -) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { - poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, originalLockId, sharesToMigrate) +) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, error) { + migratedPoolIDs, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, originalLockId, sharesToMigrate) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, 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 cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, 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,28 +113,38 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context, if err != nil { return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err } +======= + + intermediateAccount, err = k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), originalLockId) + if err != nil { + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err +>>>>>>> 7a92e782 (refactor: reduce the number of returns in superfluid migration (#6014)) } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. // This will return the coins that will be used to create the concentrated liquidity position. // It also returns the lock object that contains the remaining shares that were not used in this migration. +<<<<<<< HEAD exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, gammLockToMigrate, sharesToMigrate, tokenOutMins) +======= + exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, migratedPoolIDs.LeavingID, preMigrationLock, sharesToMigrate, tokenOutMins) +>>>>>>> 7a92e782 (refactor: reduce the number of returns in superfluid migration (#6014)) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } // Create a full range (min to max tick) concentrated liquidity position, lock it, and superfluid delegate it. - positionData, concentratedLockId, err = k.clk.CreateFullRangePositionLocked(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err := k.clk.CreateFullRangePositionLocked(ctx, migratedPoolIDs.EnteringID, sender, exitCoins, remainingLockTime) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } err = k.SuperfluidDelegate(ctx, sender.String(), concentratedLockId, intermediateAccount.ValAddr) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } - return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, migratedPoolIDs, nil } // migrateSuperfluidUnbondingBalancerToConcentrated migrates a user's superfluid unbonding balancer position to a superfluid unbonding concentrated liquidity position. @@ -147,50 +158,50 @@ func (k Keeper) migrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context sharesToMigrate sdk.Coin, synthDenomBeforeMigration string, tokenOutMins sdk.Coins, -) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { - poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) +) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, error) { + migratedPoolIDs, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, 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 cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. // This will return the coins that will be used to create the concentrated liquidity position. // 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) + exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, migratedPoolIDs.LeavingID, preMigrationLock, sharesToMigrate, tokenOutMins) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } // Create a full range (min to max tick) concentrated liquidity position. - positionData, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err := k.clk.CreateFullRangePositionUnlocking(ctx, migratedPoolIDs.EnteringID, sender, exitCoins, remainingLockTime) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } // The previous gamm intermediary account is now invalid for the new lock, since the underlying denom has changed and intermediary accounts are // created by validator address, denom, and gauge id. // We must therefore create and set a new intermediary account based on the previous validator but with the new lock's denom. - concentratedLockupDenom := cltypes.GetConcentratedLockupDenomFromPoolId(poolIdEntering) + concentratedLockupDenom := cltypes.GetConcentratedLockupDenomFromPoolId(migratedPoolIDs.EnteringID) clIntermediateAccount, err := k.GetOrCreateIntermediaryAccount(ctx, concentratedLockupDenom, valAddr) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, 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 cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } - return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, migratedPoolIDs, nil } // migrateNonSuperfluidLockBalancerToConcentrated migrates a user's non-superfluid locked or unlocking balancer position to an unlocking concentrated liquidity position. @@ -202,29 +213,29 @@ func (k Keeper) migrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context, lockId uint64, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins, -) (positionData cltypes.CreateFullRangePositionData, concentratedLockId, poolIdLeaving, poolIdEntering uint64, err error) { - poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) +) (cltypes.CreateFullRangePositionData, uint64, types.MigrationPoolIDs, error) { + migratedPoolIDs, preMigrationLock, remainingLockTime, err := k.validateMigration(ctx, sender, lockId, sharesToMigrate) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } // Force unlock, validate the provided sharesToMigrate, and exit the balancer pool. // This will return the coins that will be used to create the concentrated liquidity position. // 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) + exitCoins, err := k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, migratedPoolIDs.LeavingID, preMigrationLock, sharesToMigrate, tokenOutMins) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, 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. - positionData, concentratedLockId, err = k.clk.CreateFullRangePositionUnlocking(ctx, poolIdEntering, sender, exitCoins, remainingLockTime) + positionData, concentratedLockId, err := k.clk.CreateFullRangePositionUnlocking(ctx, migratedPoolIDs.EnteringID, sender, exitCoins, remainingLockTime) if err != nil { - return cltypes.CreateFullRangePositionData{}, 0, 0, 0, err + return cltypes.CreateFullRangePositionData{}, 0, types.MigrationPoolIDs{}, err } - return positionData, concentratedLockId, poolIdLeaving, poolIdEntering, nil + return positionData, concentratedLockId, migratedPoolIDs, nil } // routeMigration determines the status of the provided lock which is used to determine the method for migration. @@ -270,37 +281,40 @@ func (k Keeper) routeMigration(ctx sdk.Context, sender sdk.AccAddress, providedL // preMigrationLock: The original lock before migration. // remainingLockTime: The remaining time on the lock before it expires. // err: An error, if any occurred. -func (k Keeper) validateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin) (poolIdLeaving, poolIdEntering uint64, preMigrationLock *lockuptypes.PeriodLock, remainingLockTime time.Duration, err error) { +func (k Keeper) validateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId uint64, sharesToMigrate sdk.Coin) (types.MigrationPoolIDs, *lockuptypes.PeriodLock, time.Duration, error) { // Defense in depth, ensuring the sharesToMigrate contains gamm pool share prefix. if !strings.HasPrefix(sharesToMigrate.Denom, gammtypes.GAMMTokenPrefix) { - return 0, 0, &lockuptypes.PeriodLock{}, 0, types.SharesToMigrateDenomPrefixError{Denom: sharesToMigrate.Denom, ExpectedDenomPrefix: gammtypes.GAMMTokenPrefix} + return types.MigrationPoolIDs{}, &lockuptypes.PeriodLock{}, 0, types.SharesToMigrateDenomPrefixError{Denom: sharesToMigrate.Denom, ExpectedDenomPrefix: gammtypes.GAMMTokenPrefix} } // Get the balancer poolId by parsing the gamm share denom. - poolIdLeaving, err = gammtypes.GetPoolIdFromShareDenom(sharesToMigrate.Denom) + poolIdLeaving, err := gammtypes.GetPoolIdFromShareDenom(sharesToMigrate.Denom) if err != nil { - return 0, 0, &lockuptypes.PeriodLock{}, 0, err + return types.MigrationPoolIDs{}, &lockuptypes.PeriodLock{}, 0, err } // Ensure a governance sanctioned link exists between the balancer pool and a concentrated pool. - poolIdEntering, err = k.gk.GetLinkedConcentratedPoolID(ctx, poolIdLeaving) + poolIdEntering, err := k.gk.GetLinkedConcentratedPoolID(ctx, poolIdLeaving) if err != nil { - return 0, 0, &lockuptypes.PeriodLock{}, 0, err + return types.MigrationPoolIDs{}, &lockuptypes.PeriodLock{}, 0, err } // Check that lockID corresponds to sender and that the denomination of LP shares corresponds to the poolId. - preMigrationLock, err = k.validateGammLockForSuperfluidStaking(ctx, sender, poolIdLeaving, lockId) + preMigrationLock, err := k.validateGammLockForSuperfluidStaking(ctx, sender, poolIdLeaving, lockId) if err != nil { - return 0, 0, &lockuptypes.PeriodLock{}, 0, err + return types.MigrationPoolIDs{}, &lockuptypes.PeriodLock{}, 0, err } // Before we break the lock, we must note the time remaining on the lock. - remainingLockTime, err = k.getExistingLockRemainingDuration(ctx, preMigrationLock) + remainingLockTime, err := k.getExistingLockRemainingDuration(ctx, preMigrationLock) if err != nil { - return 0, 0, &lockuptypes.PeriodLock{}, 0, err + return types.MigrationPoolIDs{}, &lockuptypes.PeriodLock{}, 0, err } - return poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, nil + return types.MigrationPoolIDs{ + EnteringID: poolIdEntering, + LeavingID: poolIdLeaving, + }, preMigrationLock, remainingLockTime, nil } // validateSharesToMigrateUnlockAndExitBalancerPool validates the unlocking and exiting of gamm LP tokens from the Balancer pool. It performs the following steps: diff --git a/x/superfluid/keeper/migrate_test.go b/x/superfluid/keeper/migrate_test.go index 45b863ca318..5da1055dbdf 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. - positionData, poolIdLeaving, poolIdEntering, concentratedLockId, err := superfluidKeeper.RouteLockedBalancerToConcentratedMigration(s.Ctx, poolJoinAcc, int64(originalGammLockId), coinsToMigrate, tc.minExitCoins) + positionData, migratedPools, 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,7 +194,7 @@ func (s *KeeperTestSuite) TestRouteLockedBalancerToConcentratedMigration() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + positionData.ID, balancerPooId, migratedPools.LeavingID, clPoolId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, @@ -269,7 +269,7 @@ func (s *KeeperTestSuite) TestRouteLockedBalancerToConcentratedMigration() { // Run slashing logic if the test case involves locks and check if the new and old locks are slashed. if !tc.noLock { slashExpected := tc.superfluidDelegated || tc.superfluidUndelegating - s.SlashAndValidateResult(s.Ctx, originalGammLockId, concentratedLockId, poolIdEntering, tc.percentOfSharesToMigrate, valAddr, *balancerLock, slashExpected) + s.SlashAndValidateResult(s.Ctx, originalGammLockId, concentratedLockId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, valAddr, *balancerLock, slashExpected) } }) } @@ -350,7 +350,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidBondedBalancerToConcentrated() { balancerDelegationPre, _ := stakingKeeper.GetDelegation(s.Ctx, balancerIntermediaryAcc.GetAccAddress(), valAddr) // System under test. - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidBondedBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) + positionData, concentratedLockId, migratedPools, 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,7 +360,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidBondedBalancerToConcentrated() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + positionData.ID, balancerPooId, migratedPools.LeavingID, clPoolId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, @@ -505,7 +505,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidUnbondingBalancerToConcentrated() } // System under test. - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateSuperfluidUnbondingBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, synthLockBeforeMigration.SynthDenom, tc.tokenOutMins) + positionData, concentratedLockId, migratedPools, 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,7 +515,7 @@ func (s *KeeperTestSuite) TestMigrateSuperfluidUnbondingBalancerToConcentrated() s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + positionData.ID, balancerPooId, migratedPools.LeavingID, clPoolId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, @@ -620,7 +620,7 @@ func (s *KeeperTestSuite) TestMigrateNonSuperfluidLockBalancerToConcentrated() { s.Require().Equal(migrationType, keeper.NonSuperfluid) // System under test. - positionData, concentratedLockId, poolIdLeaving, poolIdEntering, err := superfluidKeeper.MigrateNonSuperfluidLockBalancerToConcentrated(s.Ctx, poolJoinAcc, originalGammLockId, coinsToMigrate, tc.tokenOutMins) + positionData, concentratedLockId, migratedPools, 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,7 +630,7 @@ func (s *KeeperTestSuite) TestMigrateNonSuperfluidLockBalancerToConcentrated() { s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + positionData.ID, balancerPooId, migratedPools.LeavingID, clPoolId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, @@ -703,7 +703,7 @@ func (s *KeeperTestSuite) TestMigrateUnlockedPositionFromBalancerToConcentrated( s.Require().Equal(migrationType, keeper.Unlocked) // System under test. - positionData, poolIdLeaving, poolIdEntering, err := gammKeeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, poolJoinAcc, coinsToMigrate, tc.tokenOutMins) + positionData, migratedPools, err := gammKeeper.MigrateUnlockedPositionFromBalancerToConcentrated(s.Ctx, poolJoinAcc, coinsToMigrate, tc.tokenOutMins) if tc.expectedError != nil { s.Require().ErrorContains(err, tc.expectedError.Error()) return @@ -712,7 +712,7 @@ func (s *KeeperTestSuite) TestMigrateUnlockedPositionFromBalancerToConcentrated( s.AssertEventEmitted(s.Ctx, gammtypes.TypeEvtPoolExited, 1) s.ValidateMigrateResult( - positionData.ID, balancerPooId, poolIdLeaving, clPoolId, poolIdEntering, + positionData.ID, balancerPooId, migratedPools.LeavingID, clPoolId, migratedPools.EnteringID, tc.percentOfSharesToMigrate, positionData.Liquidity, *balancerLock, joinPoolAmt, @@ -841,7 +841,7 @@ func (s *KeeperTestSuite) TestValidateMigration() { } // System under test. - poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, err := superfluidKeeper.ValidateMigration(ctx, poolJoinAcc, originalGammLockId, coinsToMigrate) + migratedPools, preMigrationLock, remainingLockTime, err := superfluidKeeper.ValidateMigration(ctx, poolJoinAcc, originalGammLockId, coinsToMigrate) if tc.expectedError != nil { s.Require().Error(err) s.Require().ErrorContains(err, tc.expectedError.Error()) @@ -849,8 +849,8 @@ func (s *KeeperTestSuite) TestValidateMigration() { } s.Require().NoError(err) - s.Require().Equal(poolIdLeaving, balancerPooId) - s.Require().Equal(poolIdEntering, clPoolId) + s.Require().Equal(migratedPools.LeavingID, balancerPooId) + s.Require().Equal(migratedPools.EnteringID, clPoolId) s.Require().Equal(preMigrationLock.GetID(), originalGammLockId) s.Require().Equal(preMigrationLock.GetCoins(), sdk.NewCoins(balancerPoolShareOut)) s.Require().Equal(preMigrationLock.GetDuration(), remainingLockTime) @@ -1403,7 +1403,7 @@ func (s *KeeperTestSuite) TestFunctional_VaryingPositions_Migrations() { preClaimBalancerPoolBalance := balancerPool.GetTotalPoolLiquidity(s.Ctx) // Run the migration. - positionData, _, _, _, 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. diff --git a/x/superfluid/keeper/msg_server.go b/x/superfluid/keeper/msg_server.go index 4ab3118202f..7dae6041c14 100644 --- a/x/superfluid/keeper/msg_server.go +++ b/x/superfluid/keeper/msg_server.go @@ -205,7 +205,7 @@ func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(go return nil, err } - positionData, poolIdLeaving, poolIdEntering, clLockId, err := server.keeper.RouteLockedBalancerToConcentratedMigration(ctx, sender, msg.LockId, msg.SharesToMigrate, msg.TokenOutMins) + positionData, migratedPoolIDs, clLockId, err := server.keeper.RouteLockedBalancerToConcentratedMigration(ctx, sender, msg.LockId, msg.SharesToMigrate, msg.TokenOutMins) if err != nil { return nil, err } @@ -213,8 +213,8 @@ func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(go ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.TypeEvtUnlockAndMigrateShares, - sdk.NewAttribute(types.AttributeKeyPoolIdEntering, strconv.FormatUint(poolIdEntering, 10)), - sdk.NewAttribute(types.AttributeKeyPoolIdLeaving, strconv.FormatUint(poolIdLeaving, 10)), + sdk.NewAttribute(types.AttributeKeyPoolIdEntering, strconv.FormatUint(migratedPoolIDs.EnteringID, 10)), + sdk.NewAttribute(types.AttributeKeyPoolIdLeaving, strconv.FormatUint(migratedPoolIDs.LeavingID, 10)), sdk.NewAttribute(types.AttributeConcentratedLockId, strconv.FormatUint(clLockId, 10)), sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributePositionId, strconv.FormatUint(positionData.ID, 10)), diff --git a/x/superfluid/types/expected_keepers.go b/x/superfluid/types/expected_keepers.go index d6c76d612b6..8b3a1fd125c 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) (positionData cltypes.CreateFullRangePositionData, poolIdLeaving, poolIdEntering uint64, err error) + MigrateUnlockedPositionFromBalancerToConcentrated(ctx sdk.Context, sender sdk.AccAddress, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (positionData cltypes.CreateFullRangePositionData, migratedPoolIDs MigrationPoolIDs, err error) } type BankKeeper interface { diff --git a/x/superfluid/types/migration.go b/x/superfluid/types/migration.go new file mode 100644 index 00000000000..80b425f2001 --- /dev/null +++ b/x/superfluid/types/migration.go @@ -0,0 +1,6 @@ +package types + +type MigrationPoolIDs struct { + LeavingID uint64 + EnteringID uint64 +}