diff --git a/x/axelarnet/keeper/migrate.go b/x/axelarnet/keeper/migrate.go index 18f7585e7..c4f83dd6a 100644 --- a/x/axelarnet/keeper/migrate.go +++ b/x/axelarnet/keeper/migrate.go @@ -11,34 +11,65 @@ import ( // Migrate6to7 returns the handler that performs in-place store migrations from version 6 to 7 func Migrate6to7(k Keeper, bankK types.BankKeeper, accountK types.AccountKeeper, nexusK types.Nexus, ibcK IBCKeeper) func(ctx sdk.Context) error { - return func(ctx sdk.Context) error { // Failed IBC transfers are held in Axelarnet module account for later retry. // This migration escrows tokens back to escrow accounts so that we can use the same code path for retry. - axelarnetModuleAccount := accountK.GetModuleAddress(types.ModuleName) - nexusModuleAccount := accountK.GetModuleAddress(nexus.ModuleName) - - balances := bankK.SpendableCoins(ctx, axelarnetModuleAccount) - for _, coin := range balances { - asset, err := nexusK.NewLockableAsset(ctx, ibcK, bankK, coin) - if err != nil { - k.Logger(ctx).Info(fmt.Sprintf("coin %s is not a lockable asset", coin), "error", err) - continue - } - - // Transfer coins from the Axelarnet module account to the Nexus module account for subsequent locking, - // as the Axelarnet module account is now restricted from sending coins. - err = bankK.SendCoinsFromModuleToModule(ctx, axelarnetModuleAccount.String(), nexusModuleAccount.String(), sdk.NewCoins(asset.GetAsset())) - if err != nil { - return err - } - - err = asset.LockFrom(ctx, nexusModuleAccount) - if err != nil { - return err - } + err := escrowFundsFromFailedTransfers(ctx, k, bankK, accountK, nexusK, ibcK) + if err != nil { + return err + } + + // All IBC transfer are routed from AxelarIBCAccount after v1.1 + // This migration updates the sender of failed transfers to AxelarIBCAccount for retry + err = migrateFailedTransfersToAxelarIBCAccount(ctx, k) + if err != nil { + return err } return nil } } + +func escrowFundsFromFailedTransfers(ctx sdk.Context, k Keeper, bankK types.BankKeeper, accountK types.AccountKeeper, nexusK types.Nexus, ibcK IBCKeeper) error { + axelarnetModuleAccount := accountK.GetModuleAddress(types.ModuleName) + nexusModuleAccount := accountK.GetModuleAddress(nexus.ModuleName) + + balances := bankK.SpendableCoins(ctx, axelarnetModuleAccount) + for _, coin := range balances { + asset, err := nexusK.NewLockableAsset(ctx, ibcK, bankK, coin) + if err != nil { + k.Logger(ctx).Info(fmt.Sprintf("coin %s is not a lockable asset", coin), "error", err) + continue + } + + // Transfer coins from the Axelarnet module account to the Nexus module account for subsequent locking, + // as the Axelarnet module account is now restricted from sending coins. + err = bankK.SendCoinsFromModuleToModule(ctx, axelarnetModuleAccount.String(), nexusModuleAccount.String(), sdk.NewCoins(asset.GetAsset())) + if err != nil { + return err + } + + err = asset.LockFrom(ctx, nexusModuleAccount) + if err != nil { + return err + } + } + + return nil +} + +func migrateFailedTransfersToAxelarIBCAccount(ctx sdk.Context, k Keeper) error { + transfers := k.getIBCTransfers(ctx) + for _, transfer := range transfers { + if transfer.Status != types.TransferFailed { + continue + } + + transfer.Sender = types.AxelarIBCAccount + if err := k.setTransfer(ctx, transfer); err != nil { + return err + } + } + + return nil +} diff --git a/x/axelarnet/keeper/migrate_test.go b/x/axelarnet/keeper/migrate_test.go index 48c084337..d3f14b45b 100644 --- a/x/axelarnet/keeper/migrate_test.go +++ b/x/axelarnet/keeper/migrate_test.go @@ -13,10 +13,13 @@ import ( "github.com/axelarnetwork/axelar-core/testutils/fake" "github.com/axelarnetwork/axelar-core/testutils/rand" "github.com/axelarnetwork/axelar-core/x/axelarnet/keeper" + "github.com/axelarnetwork/axelar-core/x/axelarnet/types" "github.com/axelarnetwork/axelar-core/x/axelarnet/types/mock" + axelartestutils "github.com/axelarnetwork/axelar-core/x/axelarnet/types/testutils" nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported" nexusmock "github.com/axelarnetwork/axelar-core/x/nexus/exported/mock" nexustypes "github.com/axelarnetwork/axelar-core/x/nexus/types" + "github.com/axelarnetwork/utils/funcs" . "github.com/axelarnetwork/utils/test" ) @@ -26,6 +29,7 @@ func TestMigrate6to7(t *testing.T) { account *mock.AccountKeeperMock nexusK *mock.NexusMock lockableAsset *nexusmock.LockableAssetMock + transfers []types.IBCTransfer ) encCfg := app.MakeEncodingConfig() @@ -59,15 +63,33 @@ func TestMigrate6to7(t *testing.T) { }, } }). - When("Axelarnet module account has balance for failed cross chain transfers", func() { + When("there are some failed transfers and Axelarnet module account has balances", func() { bank.SpendableCoinsFunc = func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { return sdk.NewCoins(rand.Coin(), rand.Coin(), rand.Coin()) } + + for i := 0; i < 50; i++ { + transfer := axelartestutils.RandomIBCTransfer() + if i%2 == 0 { + transfer.Status = types.TransferFailed + } + transfers = append(transfers, transfer) + assert.NoError(t, k.EnqueueIBCTransfer(ctx, transfer)) + } }). - Then("the migration should lock back to escrow account", func(t *testing.T) { + Then("the migration should lock back to escrow account and update sender of failed transfers", func(t *testing.T) { err := keeper.Migrate6to7(k, bank, account, nexusK, ibcK)(ctx) assert.NoError(t, err) assert.Len(t, lockableAsset.LockFromCalls(), 3) + + for _, transfer := range transfers { + actual := funcs.MustOk(k.GetTransfer(ctx, transfer.ID)) + if transfer.Status == types.TransferFailed { + assert.Equal(t, types.AxelarIBCAccount, actual.Sender) + } else { + assert.Equal(t, transfer.Sender, actual.Sender) + } + } }). Run(t) } diff --git a/x/axelarnet/keeper/msg_server.go b/x/axelarnet/keeper/msg_server.go index 804dc3fdd..4015ac332 100644 --- a/x/axelarnet/keeper/msg_server.go +++ b/x/axelarnet/keeper/msg_server.go @@ -479,8 +479,6 @@ func (s msgServer) RetryIBCTransfer(c context.Context, req *types.RetryIBCTransf if err != nil { return nil, err } - // Notice: all IBC transfer are routed from AxelarIBCAccount after v1.1 - t.Sender = types.AxelarIBCAccount err = s.ibcK.SendIBCTransfer(ctx, t) if err != nil {