diff --git a/app/upgrades_test.go b/app/upgrades_test.go index 18d18decd..d98c9009f 100644 --- a/app/upgrades_test.go +++ b/app/upgrades_test.go @@ -13,7 +13,6 @@ import ( "github.com/ingenuity-build/quicksilver/app/upgrades" "github.com/ingenuity-build/quicksilver/utils/addressutils" - icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" prtypes "github.com/ingenuity-build/quicksilver/x/participationrewards/types" tokenfactorytypes "github.com/ingenuity-build/quicksilver/x/tokenfactory/types" @@ -187,7 +186,7 @@ func (s *AppTestSuite) initTestZone() { Amount: sdk.NewCoins(sdk.NewCoin("ujunox", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("ujunox", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, } s.GetQuicksilverApp(s.chainA).InterchainstakingKeeper.SetWithdrawalRecord(s.chainA.GetContext(), wRecord) diff --git a/x/interchainstaking/keeper/callbacks_test.go b/x/interchainstaking/keeper/callbacks_test.go index 07a57acd9..1c5eaeab0 100644 --- a/x/interchainstaking/keeper/callbacks_test.go +++ b/x/interchainstaking/keeper/callbacks_test.go @@ -445,7 +445,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, @@ -464,7 +464,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(950))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, @@ -499,7 +499,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, @@ -522,7 +522,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(975))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, @@ -557,7 +557,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, @@ -580,7 +580,7 @@ func (suite *KeeperTestSuite) TestHandleValidatorCallbackJailedWithSlashing() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1000)), Txhash: "1613D2E8FBF7C7294A4D2247B55EE89FB22FC68C62D61050B944F1191DF092BD", - Status: keeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, CompletionTime: completion, } }, diff --git a/x/interchainstaking/keeper/delegation.go b/x/interchainstaking/keeper/delegation.go index e12ebcf01..7a5d6c4f9 100644 --- a/x/interchainstaking/keeper/delegation.go +++ b/x/interchainstaking/keeper/delegation.go @@ -274,7 +274,7 @@ func (k *Keeper) MakePerformanceDelegation(ctx sdk.Context, zone *types.Zone, va if zone.PerformanceAddress != nil { k.SetPerformanceDelegation(ctx, zone, types.NewDelegation(zone.PerformanceAddress.Address, validator, sdk.NewInt64Coin(zone.BaseDenom, 0))) // intentionally zero; we add a record here to stop race conditions msg := stakingTypes.MsgDelegate{DelegatorAddress: zone.PerformanceAddress.Address, ValidatorAddress: validator, Amount: sdk.NewInt64Coin(zone.BaseDenom, 10000)} - return k.SubmitTx(ctx, []sdk.Msg{&msg}, zone.PerformanceAddress, "perf/"+validator, zone.MessagesPerTx) + return k.SubmitTx(ctx, []sdk.Msg{&msg}, zone.PerformanceAddress, fmt.Sprintf("%s/%s", types.MsgTypePerformance, validator), zone.MessagesPerTx) } return nil } diff --git a/x/interchainstaking/keeper/grpc_query_test.go b/x/interchainstaking/keeper/grpc_query_test.go index 41d95de35..1b561d0f6 100644 --- a/x/interchainstaking/keeper/grpc_query_test.go +++ b/x/interchainstaking/keeper/grpc_query_test.go @@ -9,7 +9,6 @@ import ( "github.com/ingenuity-build/quicksilver/utils/addressutils" "github.com/ingenuity-build/quicksilver/utils/randomutils" - icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) @@ -689,7 +688,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))), sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)), "ABC012", - icskeeper.WithdrawStatusQueued, + types.WithdrawStatusQueued, time.Time{}, ) }, @@ -793,7 +792,7 @@ func (suite *KeeperTestSuite) TestKeeper_UserWithdrawalRecords() { sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))), sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)), "ABC012", - icskeeper.WithdrawStatusQueued, + types.WithdrawStatusQueued, time.Time{}, ) }, @@ -885,7 +884,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() { sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(15000000))), sdk.NewCoin(zone.LocalDenom, math.NewInt(15000000)), "ABC012", - icskeeper.WithdrawStatusQueued, + types.WithdrawStatusQueued, time.Time{}, ) }, diff --git a/x/interchainstaking/keeper/ibc_packet_handlers.go b/x/interchainstaking/keeper/ibc_packet_handlers.go index 67329436f..1dfe9d1d0 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers.go @@ -262,8 +262,11 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack case "/cosmos.bank.v1beta1.MsgSend": if !success { - // TODO: handle this. - return nil + if err := k.HandleFailedBankSend(ctx, src, packetData.Memo); err != nil { + k.Logger(ctx).Error("unable to handle failed MsgSend", "error", err) + return err + } + continue } response := banktypes.MsgSendResponse{} if msgResponseType != "" { @@ -432,7 +435,7 @@ func (k *Keeper) handleSendToDelegate(ctx sdk.Context, zone *types.Zone, msg *ba // if no other withdrawal records exist for this triple (i.e. no further withdrawal from this delegator account for this user (i.e. different validator)) // then burn the withdrawal_record's burn_amount. func (k *Keeper) HandleWithdrawForUser(ctx sdk.Context, zone *types.Zone, msg *banktypes.MsgSend, memo string) error { - withdrawalRecord, found := k.GetWithdrawalRecord(ctx, zone.ChainId, memo, WithdrawStatusSend) + withdrawalRecord, found := k.GetWithdrawalRecord(ctx, zone.ChainId, memo, types.WithdrawStatusSend) if !found { return errors.New("no matching withdrawal record found") } @@ -441,7 +444,7 @@ func (k *Keeper) HandleWithdrawForUser(ctx sdk.Context, zone *types.Zone, msg *b // this statement is ridiculous, but currently calling coins.Equals against coins with different denoms panics; which is pretty useless. if len(withdrawalRecord.Amount) == 1 && len(msg.Amount) == 1 && msg.Amount[0].Denom == withdrawalRecord.Amount[0].Denom && withdrawalRecord.Amount.IsEqual(msg.Amount) { k.Logger(ctx).Info("found matching withdrawal; marking as completed") - k.UpdateWithdrawalRecordStatus(ctx, &withdrawalRecord, WithdrawStatusCompleted) + k.UpdateWithdrawalRecordStatus(ctx, &withdrawalRecord, types.WithdrawStatusCompleted) if err := k.BankKeeper.BurnCoins(ctx, types.EscrowModuleAccount, sdk.NewCoins(withdrawalRecord.BurnAmount)); err != nil { // if we can't burn the coins, fail. return err @@ -460,7 +463,7 @@ func (k *Keeper) HandleWithdrawForUser(ctx sdk.Context, zone *types.Zone, msg *b if len(withdrawalRecord.Distribution) == len(dlist) { // we just removed the last element k.Logger(ctx).Info("found matching withdrawal; marking as completed") - k.UpdateWithdrawalRecordStatus(ctx, &withdrawalRecord, WithdrawStatusCompleted) + k.UpdateWithdrawalRecordStatus(ctx, &withdrawalRecord, types.WithdrawStatusCompleted) if err := k.BankKeeper.BurnCoins(ctx, types.EscrowModuleAccount, sdk.NewCoins(withdrawalRecord.BurnAmount)); err != nil { // if we can't burn the coins, fail. return err @@ -508,23 +511,26 @@ func (k *Keeper) GCCompletedRedelegations(ctx sdk.Context) error { } func (k *Keeper) HandleMaturedUnbondings(ctx sdk.Context, zone *types.Zone) error { - var err error - - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusUnbond, func(idx int64, withdrawal types.WithdrawalRecord) bool { + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, types.WithdrawStatusUnbond, func(idx int64, withdrawal types.WithdrawalRecord) bool { if ctx.BlockTime().After(withdrawal.CompletionTime) && !withdrawal.CompletionTime.Equal(time.Time{}) { // completion date has passed. k.Logger(ctx).Info("found completed unbonding") sendMsg := &banktypes.MsgSend{FromAddress: zone.DelegationAddress.GetAddress(), ToAddress: withdrawal.Recipient, Amount: sdk.Coins{withdrawal.Amount[0]}} - err = k.SubmitTx(ctx, []sdk.Msg{sendMsg}, zone.DelegationAddress, withdrawal.Txhash, zone.MessagesPerTx) + err := k.SubmitTx(ctx, []sdk.Msg{sendMsg}, zone.DelegationAddress, fmt.Sprintf("%s/%s", types.MsgTypeUnbondSend, withdrawal.Txhash), zone.MessagesPerTx) + if err != nil { k.Logger(ctx).Error("error", err) - return true + + // do not update status and increment completion time + withdrawal.DelayCompletion(ctx, types.DefaultWithdrawalRequeueDelay) + k.SetWithdrawalRecord(ctx, withdrawal) + } else { + k.Logger(ctx).Info("sending funds", "for", withdrawal.Delegator, "delegate_account", zone.DelegationAddress.GetAddress(), "to", withdrawal.Recipient, "amount", withdrawal.Amount) + k.UpdateWithdrawalRecordStatus(ctx, &withdrawal, types.WithdrawStatusSend) } - k.Logger(ctx).Info("sending funds", "for", withdrawal.Delegator, "delegate_account", zone.DelegationAddress.GetAddress(), "to", withdrawal.Recipient, "amount", withdrawal.Amount) - k.UpdateWithdrawalRecordStatus(ctx, &withdrawal, WithdrawStatusSend) } return false }) - return err + return nil } func (k *Keeper) HandleTokenizedShares(ctx sdk.Context, msg sdk.Msg, sharesAmount sdk.Coin, memo string) error { @@ -538,8 +544,7 @@ func (k *Keeper) HandleTokenizedShares(ctx sdk.Context, msg sdk.Msg, sharesAmoun } zone := k.GetZoneForDelegateAccount(ctx, tsMsg.DelegatorAddress) - - withdrawalRecord, found := k.GetWithdrawalRecord(ctx, zone.ChainId, memo, WithdrawStatusTokenize) + withdrawalRecord, found := k.GetWithdrawalRecord(ctx, zone.ChainId, memo, types.WithdrawStatusTokenize) if !found { return errors.New("no matching withdrawal record found") @@ -552,8 +557,8 @@ func (k *Keeper) HandleTokenizedShares(ctx sdk.Context, msg sdk.Msg, sharesAmoun if len(withdrawalRecord.Distribution) == len(withdrawalRecord.Amount) { // we just added the last tokens k.Logger(ctx).Info("Found matching withdrawal; marking for send") - k.DeleteWithdrawalRecord(ctx, zone.ChainId, memo, WithdrawStatusTokenize) - withdrawalRecord.Status = WithdrawStatusSend + k.DeleteWithdrawalRecord(ctx, zone.ChainId, memo, types.WithdrawStatusTokenize) + withdrawalRecord.Status = types.WithdrawStatusSend sendMsg := &banktypes.MsgSend{FromAddress: zone.DelegationAddress.Address, ToAddress: withdrawalRecord.Recipient, Amount: withdrawalRecord.Amount} err = k.SubmitTx(ctx, []sdk.Msg{sendMsg}, zone.DelegationAddress, memo, zone.MessagesPerTx) if err != nil { @@ -574,7 +579,7 @@ func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion return errors.New("invalid zero nil completion time") } - epochNumber, err := types.ParseMsgMemo(memo, types.MsgTypeRebalance) + epochNumber, err := types.ParseEpochMsgMemo(memo, types.MsgTypeRebalance) if err != nil { return err } @@ -658,7 +663,7 @@ func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion } func (k *Keeper) HandleFailedBeginRedelegate(ctx sdk.Context, msg sdk.Msg, memo string) error { - epochNumber, err := types.ParseMsgMemo(memo, types.MsgTypeRebalance) + epochNumber, err := types.ParseEpochMsgMemo(memo, types.MsgTypeRebalance) if err != nil { return err } @@ -688,7 +693,7 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. return errors.New("unable to cast source message to MsgUndelegate") } - epochNumber, err := types.ParseMsgMemo(memo, types.MsgTypeWithdrawal) + epochNumber, err := types.ParseEpochMsgMemo(memo, types.MsgTypeWithdrawal) if err != nil { return err } @@ -703,7 +708,7 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. for _, hash := range ubr.RelatedTxhash { k.Logger(ctx).Info("MsgUndelegate", "del", undelegateMsg.DelegatorAddress, "val", undelegateMsg.ValidatorAddress, "hash", hash, "chain", zone.ChainId) - record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusUnbond) + record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, types.WithdrawStatusUnbond) if !found { return fmt.Errorf("unable to lookup withdrawal record; chain: %s, hash: %s", zone.ChainId, hash) } @@ -711,7 +716,7 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. record.CompletionTime = completion } k.Logger(ctx).Info("withdrawal record to save", "rcd", record) - k.UpdateWithdrawalRecordStatus(ctx, &record, WithdrawStatusUnbond) + k.UpdateWithdrawalRecordStatus(ctx, &record, types.WithdrawStatusUnbond) } delAddr, err := addressutils.AccAddressFromBech32(undelegateMsg.DelegatorAddress, "") @@ -741,8 +746,38 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. return nil } +func (k *Keeper) HandleFailedBankSend(ctx sdk.Context, msg sdk.Msg, memo string) error { + txHash, err := types.ParseTxMsgMemo(memo, types.MsgTypeUnbondSend) + if err != nil { + return err + } + + // valid msg type bank send + sendMsg, ok := msg.(*banktypes.MsgSend) + if !ok { + return errors.New("unable to unmarshal MsgSend") + } + + // get chainID for the remote zone using msg addresses (ICA acc) + chainID, found := k.GetAddressZoneMapping(ctx, sendMsg.FromAddress) + if !found { + return fmt.Errorf("unable to find address mapping for address %s: txHash %s", sendMsg.FromAddress, txHash) + } + + wdr, found := k.GetWithdrawalRecord(ctx, chainID, txHash, types.WithdrawStatusSend) + if !found { + return fmt.Errorf("unable to find withdrawal record for %s: txHash %s", sendMsg.ToAddress, txHash) + } + + // update delayed record with status + wdr.DelayCompletion(ctx, types.DefaultWithdrawalRequeueDelay) + k.UpdateWithdrawalRecordStatus(ctx, &wdr, types.WithdrawStatusUnbond) + + return nil +} + func (k *Keeper) HandleFailedUndelegate(ctx sdk.Context, msg sdk.Msg, memo string) error { - epochNumber, err := types.ParseMsgMemo(memo, types.MsgTypeWithdrawal) + epochNumber, err := types.ParseEpochMsgMemo(memo, types.MsgTypeWithdrawal) if err != nil { return err } @@ -761,7 +796,7 @@ func (k *Keeper) HandleFailedUndelegate(ctx sdk.Context, msg sdk.Msg, memo strin } for _, hash := range ubr.RelatedTxhash { - wdr, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusUnbond) + wdr, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, types.WithdrawStatusUnbond) if !found { return fmt.Errorf("cannot find withdrawal record for %s/%s", zone.ChainId, hash) } @@ -772,7 +807,7 @@ func (k *Keeper) HandleFailedUndelegate(ctx sdk.Context, msg sdk.Msg, memo strin } wdr.Distribution = nil wdr.Requeued = true - k.UpdateWithdrawalRecordStatus(ctx, &wdr, WithdrawStatusQueued) + k.UpdateWithdrawalRecordStatus(ctx, &wdr, types.WithdrawStatusQueued) } else { // remove this validator from distribution; amend amounts; requeue. newDistribution := make([]*types.Distribution, 0) @@ -800,7 +835,7 @@ func (k *Keeper) HandleFailedUndelegate(ctx sdk.Context, msg sdk.Msg, memo strin Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewIntFromUint64(relatedAmount))), BurnAmount: sdk.NewCoin(zone.LocalDenom, relatedQAsset), Txhash: fmt.Sprintf("%064d", k.GetNextWithdrawalRecordSequence(ctx)), - Status: WithdrawStatusQueued, + Status: types.WithdrawStatusQueued, Requeued: true, } k.SetWithdrawalRecord(ctx, newWdr) diff --git a/x/interchainstaking/keeper/ibc_packet_handlers_test.go b/x/interchainstaking/keeper/ibc_packet_handlers_test.go index 8ef16c156..9e4b3b0ad 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers_test.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers_test.go @@ -20,7 +20,6 @@ import ( "github.com/ingenuity-build/quicksilver/app" "github.com/ingenuity-build/quicksilver/utils/addressutils" - icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) @@ -111,7 +110,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -164,7 +163,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, { ChainId: zone.ChainId, @@ -179,7 +178,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -232,7 +231,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -295,7 +294,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, { ChainId: zone.ChainId, @@ -310,7 +309,7 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -403,14 +402,14 @@ func (suite *KeeperTestSuite) TestHandleQueuedUnbondings() { for idx, record := range records { // check record with old status is opposite to expectedTransition (if false, this record should exist in status 3) - _, found := quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icskeeper.WithdrawStatusQueued) + _, found := quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icstypes.WithdrawStatusQueued) suite.Require().Equal(!test.expectTransition[idx], found) // check record with new status is as per expectedTransition (if false, this record should not exist in status 4) - _, found = quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icskeeper.WithdrawStatusUnbond) + _, found = quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icstypes.WithdrawStatusUnbond) suite.Require().Equal(test.expectTransition[idx], found) if test.expectTransition[idx] { - actualRecord, found := quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icskeeper.WithdrawStatusUnbond) + actualRecord, found := quicksilver.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icstypes.WithdrawStatusUnbond) suite.Require().True(found) for _, unbonding := range actualRecord.Distribution { r, found := quicksilver.InterchainstakingKeeper.GetUnbondingRecord(ctx, zone.ChainId, unbonding.Valoper, 1) @@ -448,7 +447,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUser() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -473,7 +472,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUser() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusSend, + Status: icstypes.WithdrawStatusSend, }, } }, @@ -500,7 +499,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUser() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusSend, + Status: icstypes.WithdrawStatusSend, }, { ChainId: zone.ChainId, @@ -515,7 +514,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUser() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", - Status: icskeeper.WithdrawStatusSend, + Status: icstypes.WithdrawStatusSend, }, } }, @@ -559,14 +558,14 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUser() { suite.Require().NoError(err) } - quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icskeeper.WithdrawStatusSend, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { + quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icstypes.WithdrawStatusSend, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { if withdrawal.Txhash == test.memo { suite.Require().Fail("unexpected withdrawal record; status should be Completed.") } return false }) - quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icskeeper.WithdrawStatusCompleted, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { + quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icstypes.WithdrawStatusCompleted, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { if withdrawal.Txhash != test.memo { suite.Require().Fail("unexpected withdrawal record; status should be Completed.") } @@ -601,7 +600,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUserLSM() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(2000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(2000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusSend, + Status: icstypes.WithdrawStatusSend, }, } }, @@ -627,7 +626,7 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUserLSM() { Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(2500000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(2500000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", - Status: icskeeper.WithdrawStatusSend, + Status: icstypes.WithdrawStatusSend, }, } }, @@ -675,14 +674,14 @@ func (suite *KeeperTestSuite) TestHandleWithdrawForUserLSM() { } } - quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icskeeper.WithdrawStatusSend, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { + quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icstypes.WithdrawStatusSend, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { if withdrawal.Txhash == test.memo { suite.Require().Fail("unexpected withdrawal record; status should be Completed.") } return false }) - quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icskeeper.WithdrawStatusCompleted, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { + quicksilver.InterchainstakingKeeper.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, icstypes.WithdrawStatusCompleted, func(idx int64, withdrawal icstypes.WithdrawalRecord) bool { if withdrawal.Txhash != test.memo { suite.Require().Fail("unexpected withdrawal record; status should be Completed.") } @@ -782,7 +781,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(2000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1800)), Txhash: hash1, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, } }, @@ -823,7 +822,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash1, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -833,7 +832,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: fmt.Sprintf("%064d", 1), - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -857,7 +856,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash1, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, } }, @@ -892,7 +891,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash1, - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, @@ -920,7 +919,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1500))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1350)), Txhash: hash1, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -939,7 +938,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(3000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(2700)), Txhash: hash2, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -958,7 +957,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash3, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, } }, @@ -999,7 +998,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash1, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -1014,7 +1013,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), Txhash: hash2, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -1029,7 +1028,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(600))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(540)), Txhash: hash3, - Status: icskeeper.WithdrawStatusUnbond, + Status: icstypes.WithdrawStatusUnbond, }, { ChainId: suite.chainB.ChainID, @@ -1039,7 +1038,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(500))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(450)), Txhash: fmt.Sprintf("%064d", 1), - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, { ChainId: suite.chainB.ChainID, @@ -1049,7 +1048,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(2000))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1800)), Txhash: fmt.Sprintf("%064d", 2), - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, { ChainId: suite.chainB.ChainID, @@ -1059,7 +1058,7 @@ func (suite *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(400))), BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(360)), Txhash: fmt.Sprintf("%064d", 3), - Status: icskeeper.WithdrawStatusQueued, + Status: icstypes.WithdrawStatusQueued, }, } }, diff --git a/x/interchainstaking/keeper/keeper.go b/x/interchainstaking/keeper/keeper.go index 489faaf1c..e4d407d20 100644 --- a/x/interchainstaking/keeper/keeper.go +++ b/x/interchainstaking/keeper/keeper.go @@ -322,7 +322,7 @@ func (k *Keeper) SetValidatorForZone(ctx sdk.Context, zone *types.Zone, data []b func (k *Keeper) UpdateWithdrawalRecordsForSlash(ctx sdk.Context, zone *types.Zone, valoper string, delta sdk.Dec) error { var err error - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusUnbond, func(_ int64, record types.WithdrawalRecord) bool { + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, types.WithdrawStatusUnbond, func(_ int64, record types.WithdrawalRecord) bool { recordSubAmount := sdkmath.ZeroInt() distr := record.Distribution for _, d := range distr { @@ -633,7 +633,7 @@ func (k *Keeper) Rebalance(ctx sdk.Context, zone *types.Zone, epochNumber int64) return nil } k.Logger(ctx).Info("Send rebalancing messages", "msgs", msgs) - return k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("rebalance/%d", epochNumber), zone.MessagesPerTx) + return k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("%s/%d", types.MsgTypeRebalance, epochNumber), zone.MessagesPerTx) } // UnmarshalValidatorsResponse attempts to umarshal a byte slice into a QueryValidatorsResponse. diff --git a/x/interchainstaking/keeper/keeper_test.go b/x/interchainstaking/keeper/keeper_test.go index 11f7f5131..b726f6ed8 100644 --- a/x/interchainstaking/keeper/keeper_test.go +++ b/x/interchainstaking/keeper/keeper_test.go @@ -22,7 +22,6 @@ import ( "github.com/ingenuity-build/quicksilver/utils/addressutils" "github.com/ingenuity-build/quicksilver/utils/randomutils" ics "github.com/ingenuity-build/quicksilver/x/interchainstaking" - icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) @@ -275,7 +274,7 @@ func (suite *KeeperTestSuite) TestGetUnbondingAmount() { name: "one unbonding withdrawal", records: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, expected: math.NewInt(3000000), @@ -284,7 +283,7 @@ func (suite *KeeperTestSuite) TestGetUnbondingAmount() { name: "one non-unbonding withdrawal", records: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusQueued, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusQueued, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, expected: math.ZeroInt(), @@ -294,9 +293,9 @@ func (suite *KeeperTestSuite) TestGetUnbondingAmount() { records: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) out = append(out, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, ) return out }, @@ -307,9 +306,9 @@ func (suite *KeeperTestSuite) TestGetUnbondingAmount() { records: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) out = append(out, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icskeeper.WithdrawStatusQueued, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icskeeper.WithdrawStatusCompleted, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icstypes.WithdrawStatusQueued, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icstypes.WithdrawStatusCompleted, Txhash: randomutils.GenerateRandomHashAsHex(64)}, ) return out }, @@ -379,7 +378,7 @@ func (suite *KeeperTestSuite) TestGetRatio() { name: "one withdrawal, no delegation, expect 1.0", records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, delegations: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.Delegation { @@ -393,7 +392,7 @@ func (suite *KeeperTestSuite) TestGetRatio() { name: "one withdrawals, one delegation, one unbonding, expect 1.0", records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, delegations: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.Delegation { @@ -409,7 +408,7 @@ func (suite *KeeperTestSuite) TestGetRatio() { name: "one non-unbond withdrawals, one delegation, one unbonding, expect 1.0", records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusCompleted, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusCompleted, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, delegations: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.Delegation { @@ -426,9 +425,9 @@ func (suite *KeeperTestSuite) TestGetRatio() { records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) out = append(out, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(10000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, ) return out }, @@ -446,8 +445,8 @@ func (suite *KeeperTestSuite) TestGetRatio() { records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) out = append(out, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, - icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, + icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(1500000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}, ) return out }, @@ -464,7 +463,7 @@ func (suite *KeeperTestSuite) TestGetRatio() { name: "multi unbonding withdrawal, delegation, gt 1.0", records: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.WithdrawalRecord { out := make([]icstypes.WithdrawalRecord, 0) - out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icskeeper.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) + out = append(out, icstypes.WithdrawalRecord{ChainId: zone.ChainId, Delegator: zone.DelegationAddress.Address, Recipient: addressutils.GenerateAddressForTestWithPrefix(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, math.NewInt(3000000))), Status: icstypes.WithdrawStatusUnbond, Txhash: randomutils.GenerateRandomHashAsHex(64)}) return out }, delegations: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) []icstypes.Delegation { diff --git a/x/interchainstaking/keeper/redemptions.go b/x/interchainstaking/keeper/redemptions.go index 60a9aefd1..a1a23e6c0 100644 --- a/x/interchainstaking/keeper/redemptions.go +++ b/x/interchainstaking/keeper/redemptions.go @@ -63,7 +63,7 @@ func (k *Keeper) processRedemptionForLsm(ctx sdk.Context, zone *types.Zone, send for _, msg := range msgs { sdkMsgs = append(sdkMsgs, sdk.Msg(msg)) } - k.AddWithdrawalRecord(ctx, zone.ChainId, sender.String(), []*types.Distribution{}, destination, sdk.Coins{}, burnAmount, hash, WithdrawStatusTokenize, time.Unix(0, 0)) + k.AddWithdrawalRecord(ctx, zone.ChainId, sender.String(), []*types.Distribution{}, destination, sdk.Coins{}, burnAmount, hash, types.WithdrawStatusTokenize, time.Unix(0, 0)) return k.SubmitTx(ctx, sdkMsgs, zone.DelegationAddress, hash, zone.MessagesPerTx) } @@ -90,7 +90,7 @@ func (k *Keeper) queueRedemption( amount, burnAmount, hash, - WithdrawStatusQueued, + types.WithdrawStatusQueued, time.Time{}, ) @@ -140,7 +140,7 @@ func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch return err } - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusQueued, func(idx int64, withdrawal types.WithdrawalRecord) bool { + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, types.WithdrawStatusQueued, func(idx int64, withdrawal types.WithdrawalRecord) bool { k.Logger(ctx).Info("handling queued withdrawal request", "from", withdrawal.Delegator, "to", withdrawal.Recipient, "amount", withdrawal.Amount) if len(withdrawal.Amount) == 0 { k.Logger(ctx).Error("withdrawal %s has no amount set; cannot process...", withdrawal.Txhash) @@ -220,12 +220,12 @@ WITHDRAWAL: } for _, hash := range utils.Keys(txDistrsMap) { - record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusQueued) + record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, types.WithdrawStatusQueued) if !found { return errors.New("unable to find withdrawal record") } record.Distribution = txDistrsMap[hash] - k.UpdateWithdrawalRecordStatus(ctx, &record, WithdrawStatusUnbond) + k.UpdateWithdrawalRecordStatus(ctx, &record, types.WithdrawStatusUnbond) } if len(txHashes) == 0 { @@ -242,7 +242,7 @@ WITHDRAWAL: k.Logger(ctx).Info("unbonding messages to send", "msg", msgs) - err = k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("withdrawal/%d", epoch), zone.MessagesPerTx) + err = k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("%s/%d", types.MsgTypeWithdrawal, epoch), zone.MessagesPerTx) if err != nil { return err } @@ -260,10 +260,10 @@ WITHDRAWAL: func (k *Keeper) GCCompletedUnbondings(ctx sdk.Context, zone *types.Zone) error { var err error - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusCompleted, func(idx int64, withdrawal types.WithdrawalRecord) bool { + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, types.WithdrawStatusCompleted, func(idx int64, withdrawal types.WithdrawalRecord) bool { if ctx.BlockTime().After(withdrawal.CompletionTime.Add(24 * time.Hour)) { k.Logger(ctx).Info("garbage collecting completed unbondings") - k.DeleteWithdrawalRecord(ctx, zone.ChainId, withdrawal.Txhash, WithdrawStatusCompleted) + k.DeleteWithdrawalRecord(ctx, zone.ChainId, withdrawal.Txhash, types.WithdrawStatusCompleted) } return false }) diff --git a/x/interchainstaking/keeper/withdrawal_record.go b/x/interchainstaking/keeper/withdrawal_record.go index 182f9dc05..056c2ef0f 100644 --- a/x/interchainstaking/keeper/withdrawal_record.go +++ b/x/interchainstaking/keeper/withdrawal_record.go @@ -11,15 +11,6 @@ import ( "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) -const ( - // setting WithdrawStatusTokenize as 0 causes the value to be omitted when (un)marshalling :/. - WithdrawStatusTokenize int32 = iota + 1 - WithdrawStatusQueued int32 = iota + 1 - WithdrawStatusUnbond int32 = iota + 1 - WithdrawStatusSend int32 = iota + 1 - WithdrawStatusCompleted int32 = iota + 1 -) - func (k *Keeper) GetNextWithdrawalRecordSequence(ctx sdk.Context) (sequence uint64) { store := prefix.NewStore(ctx.KVStore(k.storeKey), nil) bz := store.Get(types.KeyPrefixRequeuedWithdrawalRecordSeq) diff --git a/x/interchainstaking/keeper/zones.go b/x/interchainstaking/keeper/zones.go index b54f626e7..8d6c25388 100644 --- a/x/interchainstaking/keeper/zones.go +++ b/x/interchainstaking/keeper/zones.go @@ -97,7 +97,7 @@ func (k *Keeper) GetDelegatedAmount(ctx sdk.Context, zone *types.Zone) sdk.Coin func (k *Keeper) GetUnbondingAmount(ctx sdk.Context, zone *types.Zone) sdk.Coin { out := sdk.NewCoin(zone.BaseDenom, sdk.ZeroInt()) - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusUnbond, func(index int64, wr types.WithdrawalRecord) (stop bool) { + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, types.WithdrawStatusUnbond, func(index int64, wr types.WithdrawalRecord) (stop bool) { out = out.Add(wr.Amount[0]) return false }) diff --git a/x/interchainstaking/types/ibc_packet.go b/x/interchainstaking/types/ibc_packet.go index bcd14d86f..07c353cf8 100644 --- a/x/interchainstaking/types/ibc_packet.go +++ b/x/interchainstaking/types/ibc_packet.go @@ -1,28 +1,45 @@ package types import ( + "errors" "fmt" "strconv" "strings" ) const ( - MsgTypeWithdrawal = "withdrawal" - MsgTypeRebalance = "rebalance" + MsgTypeWithdrawal = "withdrawal" + MsgTypeRebalance = "rebalance" + MsgTypeUnbondSend = "unbondSend" + MsgTypePerformance = "perf" // TransferPort is the portID for ibc transfer module. TransferPort = "transfer" ) -func ParseMsgMemo(memo, msgType string) (epochNumber int64, err error) { +var ( + ErrUnexpectedEpochMsgMemo = errors.New("unexpected epoch memo format") + ErrUnexpectedTxMsgMemo = errors.New("unexpected tx memo format") +) + +func ParseEpochMsgMemo(memo, msgType string) (epochNumber int64, err error) { parts := strings.Split(memo, "/") if len(parts) != 2 || parts[0] != msgType { - return 0, fmt.Errorf("unexpected epoch %s memo format", msgType) + return 0, fmt.Errorf("msg type %s: %w", msgType, ErrUnexpectedEpochMsgMemo) } epochNumber, err = strconv.ParseInt(parts[1], 10, 64) if err != nil { - return 0, fmt.Errorf("unexpected epoch %s memo format: %w", msgType, err) + return 0, fmt.Errorf("msg type %s: %w: %w", msgType, err, ErrUnexpectedEpochMsgMemo) } return epochNumber, err } + +func ParseTxMsgMemo(memo, msgType string) (txHash string, err error) { + parts := strings.Split(memo, "/") + if len(parts) != 2 || parts[0] != msgType { + return "", fmt.Errorf("msg type %s: %w", msgType, ErrUnexpectedTxMsgMemo) + } + + return parts[1], err +} diff --git a/x/interchainstaking/types/ibc_packet_test.go b/x/interchainstaking/types/ibc_packet_test.go index 66ba073b4..3b1cba61c 100644 --- a/x/interchainstaking/types/ibc_packet_test.go +++ b/x/interchainstaking/types/ibc_packet_test.go @@ -45,7 +45,7 @@ func TestParseMsgMemo(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - epochNumber, err := types.ParseMsgMemo(tt.memo, tt.msgType) + epochNumber, err := types.ParseEpochMsgMemo(tt.memo, tt.msgType) if tt.wantErr { t.Logf("Error:\n%v\n", err) require.Error(t, err) diff --git a/x/interchainstaking/types/withdrawal_record.go b/x/interchainstaking/types/withdrawal_record.go new file mode 100644 index 000000000..07a5d3e6f --- /dev/null +++ b/x/interchainstaking/types/withdrawal_record.go @@ -0,0 +1,25 @@ +package types + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + DefaultWithdrawalRequeueDelay = 6 * time.Hour + + // setting WithdrawStatusTokenize as 0 causes the value to be omitted when (un)marshalling :/. + WithdrawStatusTokenize int32 = iota + 1 + WithdrawStatusQueued int32 = iota + 1 + WithdrawStatusUnbond int32 = iota + 1 + WithdrawStatusSend int32 = iota + 1 + WithdrawStatusCompleted int32 = iota + 1 +) + +// DelayCompletion updates a withdrawal record completion date to: +// +// updatedCompletion = currentTime + delay +func (w *WithdrawalRecord) DelayCompletion(ctx sdk.Context, delay time.Duration) { + w.CompletionTime = ctx.BlockTime().Add(delay) +} diff --git a/x/interchainstaking/types/withdrawal_record_test.go b/x/interchainstaking/types/withdrawal_record_test.go new file mode 100644 index 000000000..817532f9d --- /dev/null +++ b/x/interchainstaking/types/withdrawal_record_test.go @@ -0,0 +1,29 @@ +package types_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" +) + +func TestWithdrawalRecord_DelayCompletion(t *testing.T) { + // test context + ctx := sdk.Context{}.WithBlockTime(time.Now()) + + wdr := types.WithdrawalRecord{ + ChainId: "test", + Delegator: "test", + Recipient: "test", + BurnAmount: sdk.NewCoin("test", sdk.NewInt(10000)), + Txhash: "test", + Status: types.WithdrawStatusSend, + CompletionTime: ctx.BlockTime(), + } + + wdr.DelayCompletion(ctx, time.Hour) + require.Equal(t, ctx.BlockTime().Add(time.Hour), wdr.CompletionTime) +}