Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Message for Staking Conversion #5949

Merged
merged 33 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5f48cb3
WIP
mattverse Aug 2, 2023
2526268
Almost done, need more test cases...
mattverse Aug 3, 2023
9f10685
Finish adding test cases
mattverse Aug 4, 2023
8516a9b
Use val set
mattverse Aug 4, 2023
4986e0e
Add changelog
mattverse Aug 4, 2023
18e8898
Merge branch 'main' into mattverse/stake-multi0msg
devbot-wizard Aug 7, 2023
6000313
Fix simple problems
devbot-wizard Aug 7, 2023
343be73
Update tx.pb.go
ValarDragon Aug 7, 2023
1bef463
Remove partial unlocking
mattverse Aug 8, 2023
0898bdc
Use val set delegation and edit test cases
mattverse Aug 8, 2023
acd179e
Update proto/osmosis/superfluid/tx.proto
mattverse Aug 8, 2023
693c4e2
Update x/superfluid/keeper/stake.go
mattverse Aug 8, 2023
be4c03a
Romans comment, add balancer check
mattverse Aug 8, 2023
c89e9c3
Adam's comment
mattverse Aug 8, 2023
23f53c3
Change errors from bool to check error
mattverse Aug 8, 2023
b953043
Merge branch 'main' into mattverse/stake-multi0msg
czarcas7ic Aug 8, 2023
0c5b652
Add validate basic, bring back partial share migration for liquid gam…
mattverse Aug 9, 2023
69f6b39
Try abstracting check logics from test
mattverse Aug 9, 2023
06d1231
Merge branch 'main' into mattverse/stake-multi0msg
mattverse Aug 9, 2023
96f486b
Romans comment
mattverse Aug 10, 2023
306a955
Merge branch 'main' into mattverse/stake-multi0msg
mattverse Aug 10, 2023
ba1d943
Add cli
mattverse Aug 10, 2023
c8b9f31
Fix cli
mattverse Aug 10, 2023
0e9eeb1
Update x/superfluid/keeper/stake.go
czarcas7ic Aug 10, 2023
97c80f2
Update x/superfluid/client/cli/tx.go
czarcas7ic Aug 10, 2023
a2ad24b
Update x/superfluid/keeper/stake.go
czarcas7ic Aug 10, 2023
18f4bd7
Roman and Adam
mattverse Aug 11, 2023
d7e9511
Fix merge conflict
mattverse Aug 11, 2023
e5a054c
Update x/superfluid/keeper/stake.go
czarcas7ic Aug 11, 2023
33ac505
fix merge conflict
mattverse Aug 12, 2023
fe4b64c
Adams comment
mattverse Aug 12, 2023
c7b9fdb
Update x/superfluid/keeper/stake.go
mattverse Aug 14, 2023
9244686
Romans comments
mattverse Aug 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ linters:
enable:
- asciicheck
- bidichk
- depguard
mattverse marked this conversation as resolved.
Show resolved Hide resolved
- durationcheck
- errcheck
- errname
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#5874](https://github.com/osmosis-labs/osmosis/pull/5874) Remove Partial Migration from superfluid migration to CL
* [#5901](https://github.com/osmosis-labs/osmosis/pull/5901) Adding support for CW pools in ProtoRev
* [#5937](https://github.com/osmosis-labs/osmosis/pull/5937) feat: add SetScalingFactorController gov prop
* [#5949](https://github.com/osmosis-labs/osmosis/pull/5949) Add message to convert from superfluid / locks to native staking directly.

### BugFix

Expand Down
10 changes: 5 additions & 5 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,6 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appKeepers.ConcentratedLiquidityKeeper.SetIncentivesKeeper(appKeepers.IncentivesKeeper)
appKeepers.GAMMKeeper.SetIncentivesKeeper(appKeepers.IncentivesKeeper)

appKeepers.SuperfluidKeeper = superfluidkeeper.NewKeeper(
appKeepers.keys[superfluidtypes.StoreKey], appKeepers.GetSubspace(superfluidtypes.ModuleName),
*appKeepers.AccountKeeper, appKeepers.BankKeeper, appKeepers.StakingKeeper, appKeepers.DistrKeeper, appKeepers.EpochsKeeper, appKeepers.LockupKeeper, appKeepers.GAMMKeeper, appKeepers.IncentivesKeeper,
lockupkeeper.NewMsgServerImpl(appKeepers.LockupKeeper), appKeepers.ConcentratedLiquidityKeeper)

mintKeeper := mintkeeper.NewKeeper(
appKeepers.keys[minttypes.StoreKey],
appKeepers.GetSubspace(minttypes.ModuleName),
Expand Down Expand Up @@ -443,6 +438,11 @@ func (appKeepers *AppKeepers) InitNormalKeepers(

appKeepers.ValidatorSetPreferenceKeeper = &validatorSetPreferenceKeeper

appKeepers.SuperfluidKeeper = superfluidkeeper.NewKeeper(
mattverse marked this conversation as resolved.
Show resolved Hide resolved
appKeepers.keys[superfluidtypes.StoreKey], appKeepers.GetSubspace(superfluidtypes.ModuleName),
*appKeepers.AccountKeeper, appKeepers.BankKeeper, appKeepers.StakingKeeper, appKeepers.DistrKeeper, appKeepers.EpochsKeeper, appKeepers.LockupKeeper, appKeepers.GAMMKeeper, appKeepers.IncentivesKeeper,
lockupkeeper.NewMsgServerImpl(appKeepers.LockupKeeper), appKeepers.ConcentratedLiquidityKeeper, appKeepers.PoolManagerKeeper, appKeepers.ValidatorSetPreferenceKeeper)

// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
supportedFeatures := "iterator,staking,stargate,osmosis,cosmwasm_1_1,cosmwasm_1_2"
Expand Down
43 changes: 43 additions & 0 deletions proto/osmosis/superfluid/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ service Msg {
rpc AddToConcentratedLiquiditySuperfluidPosition(
MsgAddToConcentratedLiquiditySuperfluidPosition)
returns (MsgAddToConcentratedLiquiditySuperfluidPositionResponse);

// UnbondConvertAndStake breaks all locks / superfluid staked assets,
// converts them to osmo then stakes the osmo to the designated validator.
rpc UnbondConvertAndStake(MsgUnbondConvertAndStake)
returns (MsgUnbondConvertAndStakeResponse);
}

message MsgSuperfluidDelegate {
Expand Down Expand Up @@ -231,4 +236,42 @@ message MsgAddToConcentratedLiquiditySuperfluidPositionResponse {
(gogoproto.nullable) = false
];
uint64 lock_id = 4 [ (gogoproto.moretags) = "yaml:\"lock_id\"" ];
}

// ===================== MsgUnbondConvertAndStake
message MsgUnbondConvertAndStake {
option (amino.name) = "osmosis/unbond-convert-and-stake";

// lock ID to convert and stake.
// lock id with 0 should be provided if converting liquid gamm shares to stake
uint64 lock_id = 1 [ (gogoproto.moretags) = "yaml:\"lock_id\"" ];
string sender = 2 [ (gogoproto.moretags) = "yaml:\"sender\"" ];
// validator address to delegate to.
// If provided empty string, we use validator returned from valset-preference
mattverse marked this conversation as resolved.
Show resolved Hide resolved
// module.
string val_addr = 3;
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
// min_amt_to_stake indicates the minimum amount to stake after conversion
string min_amt_to_stake = 4 [
mattverse marked this conversation as resolved.
Show resolved Hide resolved
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"min_amt_to_stake\"",
(gogoproto.nullable) = false
];
// shares_to_convert_and_stake indicates amount of gamm shares to convert and
// stake.
cosmos.base.v1beta1.Coin shares_to_convert_and_stake = 5 [
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
(gogoproto.moretags) = "yaml:\"shares_to_convert_and_stake\"",
(gogoproto.nullable) = false
];
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
}

message MsgUnbondConvertAndStakeResponse {
string total_amt_staked = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"total_amt_staked\"",
(gogoproto.nullable) = false
];
string total_shares_delegated = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
25 changes: 23 additions & 2 deletions x/superfluid/keeper/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func (k Keeper) MigrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context,
return k.migrateNonSuperfluidLockBalancerToConcentrated(ctx, sender, lockId, sharesToMigrate, tokenOutMins)
}

func (k Keeper) ValidateSharesToMigrateUnlockAndExitBalancerPool(ctx sdk.Context, sender sdk.AccAddress, poolIdLeaving uint64, lock *lockuptypes.PeriodLock, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (exitCoins sdk.Coins, err error) {
return k.validateSharesToMigrateUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, lock, sharesToMigrate, tokenOutMins)
func (k Keeper) ForceUnlockAndExitBalancerPool(ctx sdk.Context, sender sdk.AccAddress, poolIdLeaving uint64, lock *lockuptypes.PeriodLock, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (exitCoins sdk.Coins, err error) {
return k.forceUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, lock, sharesToMigrate, tokenOutMins)
}

func (k Keeper) RouteMigration(ctx sdk.Context, sender sdk.AccAddress, lockId int64, sharesToMigrate sdk.Coin) (synthLockBeforeMigration lockuptypes.SyntheticLock, migrationType MigrationType, err error) {
Expand All @@ -60,3 +60,24 @@ func (k Keeper) GetExistingLockRemainingDuration(ctx sdk.Context, lock *lockupty
func (k Keeper) DistributeSuperfluidGauges(ctx sdk.Context) {
k.distributeSuperfluidGauges(ctx)
}

func (k Keeper) ConvertLockToStake(ctx sdk.Context, sender sdk.AccAddress, valAddr string, lockId uint64,
sharesToStake sdk.Coin, minAmtToStake sdk.Int) (totalAmtConverted sdk.Int, shares sdk.Dec, err error) {
return k.convertLockToStake(ctx, sender, valAddr, lockId, sharesToStake, minAmtToStake)
}
func (k Keeper) ConvertUnlockedToStake(ctx sdk.Context, sender sdk.AccAddress, valAddr string,
sharesToStake sdk.Coin, minAmtToStake sdk.Int) (totalAmtConverted sdk.Int, shares sdk.Dec, err error) {
return k.convertUnlockedToStake(ctx, sender, valAddr, sharesToStake, minAmtToStake)
}

func (k Keeper) ValidateUnbondConvertAndStake(ctx sdk.Context, sharesToMigrate sdk.Coin) (poolIdLeaving uint64, err error) {
return k.validateUnbondConvertAndStake(ctx, sharesToMigrate)
}

func (k Keeper) ConvertGammSharesToOsmoAndStake(
ctx sdk.Context,
sender sdk.AccAddress, valAddr string,
poolIdLeaving uint64, exitCoins sdk.Coins, minAmtToStake sdk.Int,
) (totalAmtCoverted sdk.Int, shares sdk.Dec, err error) {
return k.convertGammSharesToOsmoAndStake(ctx, sender, valAddr, poolIdLeaving, exitCoins, minAmtToStake)
}
24 changes: 14 additions & 10 deletions x/superfluid/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,25 @@ type Keeper struct {
storeKey sdk.StoreKey
paramSpace paramtypes.Subspace

ak authkeeper.AccountKeeper
bk types.BankKeeper
sk types.StakingKeeper
ck types.CommunityPoolKeeper
ek types.EpochKeeper
lk types.LockupKeeper
gk types.GammKeeper
ik types.IncentivesKeeper
clk types.ConcentratedKeeper
ak authkeeper.AccountKeeper
bk types.BankKeeper
sk types.StakingKeeper
ck types.CommunityPoolKeeper
ek types.EpochKeeper
lk types.LockupKeeper
gk types.GammKeeper
ik types.IncentivesKeeper
clk types.ConcentratedKeeper
pmk types.PoolManagerKeeper
vspk types.ValSetPreferenceKeeper

lms types.LockupMsgServer
}

var _ govtypes.StakingKeeper = (*Keeper)(nil)

// NewKeeper returns an instance of Keeper.
func NewKeeper(storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak authkeeper.AccountKeeper, bk types.BankKeeper, sk types.StakingKeeper, dk types.CommunityPoolKeeper, ek types.EpochKeeper, lk types.LockupKeeper, gk types.GammKeeper, ik types.IncentivesKeeper, lms types.LockupMsgServer, clk types.ConcentratedKeeper) *Keeper {
func NewKeeper(storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak authkeeper.AccountKeeper, bk types.BankKeeper, sk types.StakingKeeper, dk types.CommunityPoolKeeper, ek types.EpochKeeper, lk types.LockupKeeper, gk types.GammKeeper, ik types.IncentivesKeeper, lms types.LockupMsgServer, clk types.ConcentratedKeeper, pmk types.PoolManagerKeeper, vspk types.ValSetPreferenceKeeper) *Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
Expand All @@ -52,6 +54,8 @@ func NewKeeper(storeKey sdk.StoreKey, paramSpace paramtypes.Subspace, ak authkee
gk: gk,
ik: ik,
clk: clk,
pmk: pmk,
vspk: vspk,

lms: lms,
}
Expand Down
36 changes: 22 additions & 14 deletions x/superfluid/keeper/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,24 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context,

// 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{}

intermediateAccount, err = k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), originalLockId)
intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), originalLockId)
mattverse marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 0, 0, 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.forceUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, preMigrationLock, sharesToMigrate, tokenOutMins)
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 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, 0, types.TwoTokenBalancerPoolError{NumberOfTokens: len(exitCoins)}
}
mattverse marked this conversation as resolved.
Show resolved Hide resolved

// 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)
if err != nil {
Expand Down Expand Up @@ -153,11 +156,16 @@ func (k Keeper) migrateSuperfluidUnbondingBalancerToConcentrated(ctx sdk.Context
// 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.forceUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, preMigrationLock, sharesToMigrate, tokenOutMins)
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 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, 0, types.TwoTokenBalancerPoolError{NumberOfTokens: len(exitCoins)}
}

// 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)
if err != nil {
Expand Down Expand Up @@ -201,11 +209,16 @@ func (k Keeper) migrateNonSuperfluidLockBalancerToConcentrated(ctx sdk.Context,
// 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.forceUnlockAndExitBalancerPool(ctx, sender, poolIdLeaving, preMigrationLock, sharesToMigrate, tokenOutMins)
if err != nil {
return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, 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, 0, types.TwoTokenBalancerPoolError{NumberOfTokens: len(exitCoins)}
}

// 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.
Expand Down Expand Up @@ -293,15 +306,15 @@ func (k Keeper) validateMigration(ctx sdk.Context, sender sdk.AccAddress, lockId
return poolIdLeaving, poolIdEntering, preMigrationLock, remainingLockTime, nil
}

// validateSharesToMigrateUnlockAndExitBalancerPool validates the unlocking and exiting of gamm LP tokens from the Balancer pool. It performs the following steps:
// forceUnlockAndExitBalancerPool validates the unlocking and exiting of gamm LP tokens from the Balancer pool. It performs the following steps:
//
// 1. Completes the unlocking process / deletes synthetic locks for the provided lock.
// 2. If shares to migrate are not specified, all shares in the lock are migrated.
// 3. Ensures that the number of shares to migrate is less than or equal to the number of shares in the lock.
// 4. Exits the position in the Balancer pool.
// 5. Ensures that exactly two coins are returned.
// 6. Any remaining shares that were not migrated are re-locked as a new lock for the remaining time on the lock.
func (k Keeper) validateSharesToMigrateUnlockAndExitBalancerPool(ctx sdk.Context, sender sdk.AccAddress, poolIdLeaving uint64, lock *lockuptypes.PeriodLock, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (exitCoins sdk.Coins, err error) {
func (k Keeper) forceUnlockAndExitBalancerPool(ctx sdk.Context, sender sdk.AccAddress, poolIdLeaving uint64, lock *lockuptypes.PeriodLock, sharesToMigrate sdk.Coin, tokenOutMins sdk.Coins) (exitCoins sdk.Coins, err error) {
// validateMigration ensures that the preMigrationLock contains coins of length 1.
gammSharesInLock := lock.Coins[0]

Expand All @@ -320,7 +333,7 @@ func (k Keeper) validateSharesToMigrateUnlockAndExitBalancerPool(ctx sdk.Context
return sdk.Coins{}, types.MigratePartialSharesError{SharesToMigrate: sharesToMigrate.Amount.String(), SharesInLock: gammSharesInLock.Amount.String()}
}

// Force migrate, which breaks and deletes associated synthetic locks.
// Force migrate, which breaks and deletes associated synthetic locks (if exists).
err = k.lk.ForceUnlock(ctx, *lock)
if err != nil {
return sdk.Coins{}, err
Expand All @@ -332,10 +345,5 @@ func (k Keeper) validateSharesToMigrateUnlockAndExitBalancerPool(ctx sdk.Context
return sdk.Coins{}, err
}

// Defense in depth, ensuring we are returning exactly two coins.
if len(exitCoins) != 2 {
czarcas7ic marked this conversation as resolved.
Show resolved Hide resolved
return sdk.Coins{}, types.TwoTokenBalancerPoolError{NumberOfTokens: len(exitCoins)}
}

return exitCoins, nil
}
9 changes: 2 additions & 7 deletions x/superfluid/keeper/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ func (s *KeeperTestSuite) TestValidateMigration() {
}
}

func (s *KeeperTestSuite) TestValidateSharesToMigrateUnlockAndExitBalancerPool() {
func (s *KeeperTestSuite) TestforceUnlockAndExitBalancerPool() {
defaultJoinTime := s.Ctx.BlockTime()
type sendTest struct {
overwritePreMigrationLock bool
Expand Down Expand Up @@ -831,11 +831,6 @@ func (s *KeeperTestSuite) TestValidateSharesToMigrateUnlockAndExitBalancerPool()
overwritePoolId: true,
expectedError: fmt.Errorf("pool with ID %d does not exist", 2),
},
"error: attempt to leave a pool that has more than two denoms": {
AlpinYukseloglu marked this conversation as resolved.
Show resolved Hide resolved
percentOfSharesToMigrate: sdk.MustNewDecFromStr("1"),
overwritePool: true,
expectedError: types.TwoTokenBalancerPoolError{NumberOfTokens: 4},
},
"error: happy path (full shares), token out mins is more than exit coins": {
percentOfSharesToMigrate: sdk.MustNewDecFromStr("1"),
tokenOutMins: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(100000))),
Expand Down Expand Up @@ -917,7 +912,7 @@ func (s *KeeperTestSuite) TestValidateSharesToMigrateUnlockAndExitBalancerPool()
}

// System under test
exitCoins, err := superfluidKeeper.ValidateSharesToMigrateUnlockAndExitBalancerPool(ctx, poolJoinAcc, balancerPooId, lock, coinsToMigrate, tc.tokenOutMins)
exitCoins, err := superfluidKeeper.ForceUnlockAndExitBalancerPool(ctx, poolJoinAcc, balancerPooId, lock, coinsToMigrate, tc.tokenOutMins)
if tc.expectedError != nil {
s.Require().Error(err)
s.Require().ErrorContains(err, tc.expectedError.Error())
Expand Down
11 changes: 11 additions & 0 deletions x/superfluid/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,14 @@ func (server msgServer) AddToConcentratedLiquiditySuperfluidPosition(goCtx conte

return &types.MsgAddToConcentratedLiquiditySuperfluidPositionResponse{PositionId: newPositionId, Amount0: actualAmount0, Amount1: actualAmount1, LockId: newLockId, NewLiquidity: newLiquidity}, nil
}

func (server msgServer) UnbondConvertAndStake(goCtx context.Context, msg *types.MsgUnbondConvertAndStake) (*types.MsgUnbondConvertAndStakeResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

totalAmtConverted, totalSharesDelegated, err := server.keeper.UnbondConvertAndStake(ctx, msg.LockId, msg.Sender, msg.ValAddr, msg.MinAmtToStake, msg.SharesToConvertAndStake)
if err != nil {
return nil, err
}

return &types.MsgUnbondConvertAndStakeResponse{TotalAmtStaked: totalAmtConverted, TotalSharesDelegated: totalSharesDelegated}, nil
}
Loading