Skip to content

Commit

Permalink
Disable lsm unbond (#997)
Browse files Browse the repository at this point in the history
* fix: use native unbonding, as it is more reliable

* fix: disable lsm unbond test as this now fails but to previous commit

* comment out unused function to placate golint-ci

---------

Co-authored-by: Jacob Gadikian <[email protected]>
  • Loading branch information
Joe Bowman and faddat authored Jan 5, 2024
1 parent 14015c9 commit 14f5977
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 122 deletions.
10 changes: 2 additions & 8 deletions x/interchainstaking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,8 @@ func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgReques
return nil, fmt.Errorf("unable to send coins to escrow account: %w", err)
}

if zone.LiquidityModule {
if err := k.processRedemptionForLsm(ctx, zone, sender, msg.DestinationAddress, nativeTokens, msg.Value, hashString); err != nil {
return nil, fmt.Errorf("unable to process redemption for LSM: %w", err)
}
} else {
if err := k.queueRedemption(ctx, zone, sender, msg.DestinationAddress, nativeTokens, msg.Value, hashString); err != nil {
return nil, fmt.Errorf("unable to queue redemption: %w", err)
}
if err := k.queueRedemption(ctx, zone, sender, msg.DestinationAddress, nativeTokens, msg.Value, hashString); err != nil {
return nil, fmt.Errorf("unable to queue redemption: %w", err)
}

ctx.EventManager().EmitEvents(sdk.Events{
Expand Down
98 changes: 49 additions & 49 deletions x/interchainstaking/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,55 +302,55 @@ func (suite *KeeperTestSuite) TestRequestRedemption() {
}
})

// run tests with LSM enabled.
tt.name += "_LSM_enabled"
suite.Run(tt.name, func() {
suite.SetupTest()
suite.setupTestZones()

ctx := suite.chainA.GetContext()

params := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetParams(ctx)
params.UnbondingEnabled = true
suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetParams(ctx, params)

err := suite.GetQuicksilverApp(suite.chainA).BankKeeper.MintCoins(ctx, icstypes.ModuleName, sdk.NewCoins(sdk.NewCoin("uqatom", math.NewInt(10000000))))
suite.NoError(err)
err = suite.GetQuicksilverApp(suite.chainA).BankKeeper.SendCoinsFromModuleToAccount(ctx, icstypes.ModuleName, testAccount, sdk.NewCoins(sdk.NewCoin("uqatom", math.NewInt(10000000))))
suite.NoError(err)

// enable LSM
zone, found := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetZone(ctx, suite.chainB.ChainID)
suite.True(found)
zone.LiquidityModule = true
zone.UnbondingEnabled = true
suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetZone(ctx, &zone)

validators := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetValidatorAddresses(ctx, suite.chainB.ChainID)
for _, delegation := range func(zone icstypes.Zone) []icstypes.Delegation {
out := make([]icstypes.Delegation, 0)
for _, valoper := range validators {
out = append(out, icstypes.NewDelegation(zone.DelegationAddress.Address, valoper, sdk.NewCoin(zone.BaseDenom, sdk.NewInt(3000000))))
}
return out
}(zone) {
suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetDelegation(ctx, zone.ChainId, delegation)
}

tt.malleate()

msgSrv := icskeeper.NewMsgServerImpl(suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper)
res, err := msgSrv.RequestRedemption(sdk.WrapSDKContext(suite.chainA.GetContext()), &msg)

if tt.expectErrLsm != "" {
suite.Errorf(err, tt.expectErrLsm)
suite.Nil(res)
suite.T().Logf("Error: %v", err)
} else {
suite.NoError(err)
suite.NotNil(res)
}
})
// run tests with LSM enabled. - disabled until we decide to use LSM unbonding.
// tt.name += "_LSM_enabled"
// suite.Run(tt.name, func() {
// suite.SetupTest()
// suite.setupTestZones()

// ctx := suite.chainA.GetContext()

// params := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetParams(ctx)
// params.UnbondingEnabled = true
// suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetParams(ctx, params)

// err := suite.GetQuicksilverApp(suite.chainA).BankKeeper.MintCoins(ctx, icstypes.ModuleName, sdk.NewCoins(sdk.NewCoin("uqatom", math.NewInt(10000000))))
// suite.NoError(err)
// err = suite.GetQuicksilverApp(suite.chainA).BankKeeper.SendCoinsFromModuleToAccount(ctx, icstypes.ModuleName, testAccount, sdk.NewCoins(sdk.NewCoin("uqatom", math.NewInt(10000000))))
// suite.NoError(err)

// // enable LSM
// zone, found := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetZone(ctx, suite.chainB.ChainID)
// suite.True(found)
// zone.LiquidityModule = true
// zone.UnbondingEnabled = true
// suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetZone(ctx, &zone)

// validators := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.GetValidatorAddresses(ctx, suite.chainB.ChainID)
// for _, delegation := range func(zone icstypes.Zone) []icstypes.Delegation {
// out := make([]icstypes.Delegation, 0)
// for _, valoper := range validators {
// out = append(out, icstypes.NewDelegation(zone.DelegationAddress.Address, valoper, sdk.NewCoin(zone.BaseDenom, sdk.NewInt(3000000))))
// }
// return out
// }(zone) {
// suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetDelegation(ctx, zone.ChainId, delegation)
// }

// tt.malleate()

// msgSrv := icskeeper.NewMsgServerImpl(suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper)
// res, err := msgSrv.RequestRedemption(sdk.WrapSDKContext(suite.chainA.GetContext()), &msg)

// if tt.expectErrLsm != "" {
// suite.Errorf(err, tt.expectErrLsm)
// suite.Nil(res)
// suite.T().Logf("Error: %v", err)
// } else {
// suite.NoError(err)
// suite.NotNil(res)
// }
// })

}
}
Expand Down
129 changes: 64 additions & 65 deletions x/interchainstaking/keeper/redemptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,74 +14,73 @@ import (
"github.com/quicksilver-zone/quicksilver/utils"
epochstypes "github.com/quicksilver-zone/quicksilver/x/epochs/types"
"github.com/quicksilver-zone/quicksilver/x/interchainstaking/types"
lsmstakingtypes "github.com/quicksilver-zone/quicksilver/x/lsmtypes"
)

// processRedemptionForLsm will determine based on user intent, the tokens to return to the user, generate Redeem message and send them.
func (k *Keeper) processRedemptionForLsm(ctx sdk.Context, zone *types.Zone, sender sdk.AccAddress, destination string, nativeTokens math.Int, burnAmount sdk.Coin, hash string) error {
intent, found := k.GetDelegatorIntent(ctx, zone, sender.String(), false)
// msgs is slice of MsgTokenizeShares, so we can handle dust allocation later.
msgs := make([]*lsmstakingtypes.MsgTokenizeShares, 0)
var err error
intents := intent.Intents

if !found || len(intents) == 0 {
// if user has no intent set (this can happen if redeeming tokens that were obtained offchain), use global intent.
// Note: this can be improved; user will receive a bunch of tokens.
intents, err = k.GetAggregateIntentOrDefault(ctx, zone)
if err != nil {
return err
}
}
outstanding := nativeTokens
distribution := make(map[string]uint64, 0)

availablePerValidator, _, err := k.GetUnlockedTokensForZone(ctx, zone)
if err != nil {
return err
}
for _, intent := range intents.Sort() {
thisAmount := intent.Weight.MulInt(nativeTokens).TruncateInt()
if thisAmount.GT(availablePerValidator[intent.ValoperAddress]) {
return errors.New("unable to satisfy unbond request; delegations may be locked")
}
distribution[intent.ValoperAddress] = thisAmount.Uint64()
outstanding = outstanding.Sub(thisAmount)
}

distribution[intents[0].ValoperAddress] += outstanding.Uint64()

if distribution[intents[0].ValoperAddress] > availablePerValidator[intents[0].ValoperAddress].Uint64() {
return errors.New("unable to satisfy unbond request (2); delegations may be locked")
}

for _, valoper := range utils.Keys(distribution) {
msgs = append(msgs, &lsmstakingtypes.MsgTokenizeShares{
DelegatorAddress: zone.DelegationAddress.Address,
ValidatorAddress: valoper,
Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewIntFromUint64(distribution[valoper])),
TokenizedShareOwner: destination,
})
}

sdkMsgs := make([]sdk.Msg, 0)
for _, msg := range msgs {
sdkMsgs = append(sdkMsgs, sdk.Msg(msg))
}
distributions := make([]*types.Distribution, 0)

for valoper, amount := range distribution {
newDistribution := types.Distribution{
Valoper: valoper,
Amount: amount,
}
distributions = append(distributions, &newDistribution)
}

k.AddWithdrawalRecord(ctx, zone.ChainId, sender.String(), distributions, destination, sdk.Coins{}, burnAmount, hash, types.WithdrawStatusTokenize, time.Unix(0, 0), k.EpochsKeeper.GetEpochInfo(ctx, epochstypes.EpochIdentifierEpoch).CurrentEpoch)

return k.SubmitTx(ctx, sdkMsgs, zone.DelegationAddress, hash, zone.MessagesPerTx)
}
// func (k *Keeper) processRedemptionForLsm(ctx sdk.Context, zone *types.Zone, sender sdk.AccAddress, destination string, nativeTokens math.Int, burnAmount sdk.Coin, hash string) error {
// intent, found := k.GetDelegatorIntent(ctx, zone, sender.String(), false)
// // msgs is slice of MsgTokenizeShares, so we can handle dust allocation later.
// msgs := make([]*lsmstakingtypes.MsgTokenizeShares, 0)
// var err error
// intents := intent.Intents

// if !found || len(intents) == 0 {
// // if user has no intent set (this can happen if redeeming tokens that were obtained offchain), use global intent.
// // Note: this can be improved; user will receive a bunch of tokens.
// intents, err = k.GetAggregateIntentOrDefault(ctx, zone)
// if err != nil {
// return err
// }
// }
// outstanding := nativeTokens
// distribution := make(map[string]uint64, 0)

// availablePerValidator, _, err := k.GetUnlockedTokensForZone(ctx, zone)
// if err != nil {
// return err
// }
// for _, intent := range intents.Sort() {
// thisAmount := intent.Weight.MulInt(nativeTokens).TruncateInt()
// if thisAmount.GT(availablePerValidator[intent.ValoperAddress]) {
// return errors.New("unable to satisfy unbond request; delegations may be locked")
// }
// distribution[intent.ValoperAddress] = thisAmount.Uint64()
// outstanding = outstanding.Sub(thisAmount)
// }

// distribution[intents[0].ValoperAddress] += outstanding.Uint64()

// if distribution[intents[0].ValoperAddress] > availablePerValidator[intents[0].ValoperAddress].Uint64() {
// return errors.New("unable to satisfy unbond request (2); delegations may be locked")
// }

// for _, valoper := range utils.Keys(distribution) {
// msgs = append(msgs, &lsmstakingtypes.MsgTokenizeShares{
// DelegatorAddress: zone.DelegationAddress.Address,
// ValidatorAddress: valoper,
// Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewIntFromUint64(distribution[valoper])),
// TokenizedShareOwner: destination,
// })
// }

// sdkMsgs := make([]sdk.Msg, 0)
// for _, msg := range msgs {
// sdkMsgs = append(sdkMsgs, sdk.Msg(msg))
// }
// distributions := make([]*types.Distribution, 0)

// for valoper, amount := range distribution {
// newDistribution := types.Distribution{
// Valoper: valoper,
// Amount: amount,
// }
// distributions = append(distributions, &newDistribution)
// }

// k.AddWithdrawalRecord(ctx, zone.ChainId, sender.String(), distributions, destination, sdk.Coins{}, burnAmount, hash, types.WithdrawStatusTokenize, time.Unix(0, 0), k.EpochsKeeper.GetEpochInfo(ctx, epochstypes.EpochIdentifierEpoch).CurrentEpoch)

// return k.SubmitTx(ctx, sdkMsgs, zone.DelegationAddress, hash, zone.MessagesPerTx)
// }

// queueRedemption will determine based on zone intent, the tokens to unbond, and add a withdrawal record with status QUEUED.
func (k *Keeper) queueRedemption(
Expand Down

0 comments on commit 14f5977

Please sign in to comment.