package keeper_test import ( "fmt" sdkmath "cosmossdk.io/math" sdk "git.cw.tr/mukan-network/mukan-sdk/types" banktestutil "git.cw.tr/mukan-network/mukan-sdk/x/bank/testutil" banktypes "git.cw.tr/mukan-network/mukan-sdk/x/bank/types" internaltransfertypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/transfer/internal/types" transferkeeper "git.cw.tr/mukan-network/mukan-ibc/modules/apps/transfer/keeper" transfertypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/transfer/types" ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing" ) func (suite *KeeperTestSuite) TestMigratorMigrateParams() { testCases := []struct { msg string malleate func() expectedParams transfertypes.Params }{ { "success: default params", func() { params := transfertypes.DefaultParams() subspace := suite.chainA.GetSimApp().GetSubspace(transfertypes.ModuleName) subspace.SetParamSet(suite.chainA.GetContext(), ¶ms) // set params }, transfertypes.DefaultParams(), }, } for _, tc := range testCases { suite.Run(fmt.Sprintf("case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() // explicitly set params migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) err := migrator.MigrateParams(suite.chainA.GetContext()) suite.Require().NoError(err) params := suite.chainA.GetSimApp().TransferKeeper.GetParams(suite.chainA.GetContext()) suite.Require().Equal(tc.expectedParams, params) }) } } func (suite *KeeperTestSuite) TestMigratorMigrateDenomTraceToDenom() { testCases := []struct { msg string malleate func() expectedDenoms transfertypes.Denoms }{ { "success: no trace", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "uatom", }) }, transfertypes.Denoms{ transfertypes.NewDenom("uatom"), }, }, { "success: single trace", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "uatom", Path: "transfer/channel-49", }) }, transfertypes.Denoms{ transfertypes.NewDenom("uatom", transfertypes.NewHop("transfer", "channel-49")), }, }, { "success: multiple trace", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "uatom", Path: "transfer/channel-49/transfer/channel-32/transfer/channel-2", }) }, transfertypes.Denoms{ transfertypes.NewDenom("uatom", transfertypes.NewHop("transfer", "channel-49"), transfertypes.NewHop("transfer", "channel-32"), transfertypes.NewHop("transfer", "channel-2")), }, }, { "success: many denoms", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "uatom", Path: "transfer/channel-49", }) suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "pineapple", Path: "transfer/channel-0", }) suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "apple", Path: "transfer/channel-0", }) suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "cucumber", Path: "transfer/channel-102/transfer/channel-0", }) }, transfertypes.Denoms{ transfertypes.NewDenom("apple", transfertypes.NewHop("transfer", "channel-0")), transfertypes.NewDenom("cucumber", transfertypes.NewHop("transfer", "channel-102"), transfertypes.NewHop("transfer", "channel-0")), transfertypes.NewDenom("pineapple", transfertypes.NewHop("transfer", "channel-0")), transfertypes.NewDenom("uatom", transfertypes.NewHop("transfer", "channel-49")), }, }, { "success: two slashes in base denom", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "gamm/pool/1", Path: "transfer/channel-0", }) }, transfertypes.Denoms{ transfertypes.NewDenom("gamm/pool/1", transfertypes.NewHop("transfer", "channel-0")), }, }, { "success: one slash in base denom", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "erc/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", Path: "transfer/channel-149", }) }, transfertypes.Denoms{ transfertypes.NewDenom("erc/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", transfertypes.NewHop("transfer", "channel-149")), }, }, { "success: non-standard port", func() { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace( suite.chainA.GetContext(), internaltransfertypes.DenomTrace{ BaseDenom: "uatom", Path: "transfer/channel-0/customport/channel-7", }) }, transfertypes.Denoms{ transfertypes.NewDenom("uatom", transfertypes.NewHop("transfer", "channel-0"), transfertypes.NewHop("customport", "channel-7")), }, }, } for _, tc := range testCases { suite.Run(tc.msg, func() { suite.SetupTest() // reset tc.malleate() migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) err := migrator.MigrateDenomTraceToDenom(suite.chainA.GetContext()) suite.Require().NoError(err) denoms := suite.chainA.GetSimApp().TransferKeeper.GetAllDenoms(suite.chainA.GetContext()) suite.Require().Equal(tc.expectedDenoms, denoms) // assert no leftover denom traces suite.chainA.GetSimApp().TransferKeeper.IterateDenomTraces(suite.chainA.GetContext(), func(dt internaltransfertypes.DenomTrace) (stop bool) { suite.FailNow("DenomTrace key still exists", dt) return false }, ) }) } } func (suite *KeeperTestSuite) TestMigratorMigrateDenomTraceToDenomCorruptionDetection() { testCases := []struct { name string denomTrace internaltransfertypes.DenomTrace }{ { "corrupted denom trace, denom.IBCHash() does not match", internaltransfertypes.DenomTrace{ BaseDenom: "customport/channel-0/uatom", Path: "", }, }, { "invalid denom trace, base denom is empty", internaltransfertypes.DenomTrace{ BaseDenom: "", Path: "transfer/channel-0", }, }, } for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupTest() // reset suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), tc.denomTrace) migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) suite.Panics(func() { migrator.MigrateDenomTraceToDenom(suite.chainA.GetContext()) //nolint:errcheck // we shouldn't check the error here because we want to ensure that a panic occurs. }) }) } } func (suite *KeeperTestSuite) TestMigrateTotalEscrowForDenom() { var ( path *ibctesting.Path denom string ) testCases := []struct { msg string malleate func() expectedEscrowAmt sdkmath.Int }{ { "success: one native denom escrowed in one channel", func() { denom = sdk.DefaultBondDenom escrowAddress := transfertypes.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) coin := ibctesting.TestCoin // funds the escrow account to have balance suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrowAddress, sdk.NewCoins(coin))) }, sdkmath.NewInt(100), }, { "success: one native denom escrowed in two channels", func() { denom = sdk.DefaultBondDenom extraPath := ibctesting.NewTransferPath(suite.chainA, suite.chainB) extraPath.Setup() escrowAddress1 := transfertypes.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) escrowAddress2 := transfertypes.GetEscrowAddress(extraPath.EndpointA.ChannelConfig.PortID, extraPath.EndpointA.ChannelID) coin1 := ibctesting.TestCoin coin2 := ibctesting.TestCoin // funds the escrow accounts to have balance suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrowAddress1, sdk.NewCoins(coin1))) suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrowAddress2, sdk.NewCoins(coin2))) }, sdkmath.NewInt(200), }, { "success: valid ibc denom escrowed in one channel", func() { escrowAddress := transfertypes.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) voucherDenom := transfertypes.NewDenom(sdk.DefaultBondDenom, transfertypes.NewHop(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) coin := sdk.NewCoin(voucherDenom.IBCDenom(), sdkmath.NewInt(100)) denom = voucherDenom.IBCDenom() // funds the escrow account to have balance suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrowAddress, sdk.NewCoins(coin))) }, sdkmath.NewInt(100), }, } for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) path.Setup() tc.malleate() // explicitly fund escrow account migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) suite.Require().NoError(migrator.MigrateTotalEscrowForDenom(suite.chainA.GetContext())) // check that the migration set the expected amount for both native and IBC tokens amount := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), denom) suite.Require().Equal(tc.expectedEscrowAmt, amount.Amount) }) } } func (suite *KeeperTestSuite) TestMigratorMigrateMetadata() { var ( denomTraces []internaltransfertypes.DenomTrace expectedMetadata []banktypes.Metadata ) testCases := []struct { msg string malleate func() }{ { "success with one denom trace with one hop", func() { denomTraces = []internaltransfertypes.DenomTrace{ { BaseDenom: "foo", Path: "transfer/channel-0", }, } expectedMetadata = []banktypes.Metadata{ { Description: "IBC token from transfer/channel-0/foo", DenomUnits: []*banktypes.DenomUnit{ { Denom: "foo", Exponent: 0, }, }, Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA Display: "transfer/channel-0/foo", Name: "transfer/channel-0/foo IBC token", Symbol: "FOO", }, } }, }, { "success with one denom trace with two hops", func() { denomTraces = []internaltransfertypes.DenomTrace{ { BaseDenom: "ubar", Path: "transfer/channel-1/transfer/channel-2", }, } expectedMetadata = []banktypes.Metadata{ { Description: "IBC token from transfer/channel-1/transfer/channel-2/ubar", DenomUnits: []*banktypes.DenomUnit{ { Denom: "ubar", Exponent: 0, }, }, Base: denomTraces[0].IBCDenom(), // ibc/8243B3EAA19BAB1DB3B0020B81C0C5A953E7B22C042CEE44E639A11A238BA57C Display: "transfer/channel-1/transfer/channel-2/ubar", Name: "transfer/channel-1/transfer/channel-2/ubar IBC token", Symbol: "UBAR", }, } }, }, { "success with two denom traces with one hop", func() { denomTraces = []internaltransfertypes.DenomTrace{ { BaseDenom: "foo", Path: "transfer/channel-0", }, { BaseDenom: "bar", Path: "transfer/channel-0", }, } expectedMetadata = []banktypes.Metadata{ { Description: "IBC token from transfer/channel-0/foo", DenomUnits: []*banktypes.DenomUnit{ { Denom: "foo", Exponent: 0, }, }, Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA Display: "transfer/channel-0/foo", Name: "transfer/channel-0/foo IBC token", Symbol: "FOO", }, { Description: "IBC token from transfer/channel-0/bar", DenomUnits: []*banktypes.DenomUnit{ { Denom: "bar", Exponent: 0, }, }, Base: denomTraces[1].IBCDenom(), // ibc/E1530E21F1848B6C29C9E89256D43E294976897611A61741CACBA55BE21736F5 Display: "transfer/channel-0/bar", Name: "transfer/channel-0/bar IBC token", Symbol: "BAR", }, } }, }, { "success with two denom traces, metadata for one of them already exists", func() { denomTraces = []internaltransfertypes.DenomTrace{ { BaseDenom: "foo", Path: "transfer/channel-0", }, { BaseDenom: "bar", Path: "transfer/channel-0", }, } expectedMetadata = []banktypes.Metadata{ { Description: "IBC token from transfer/channel-0/foo", DenomUnits: []*banktypes.DenomUnit{ { Denom: "foo", Exponent: 0, }, }, Base: denomTraces[0].IBCDenom(), // ibc/EB7094899ACFB7A6F2A67DB084DEE2E9A83DEFAA5DEF92D9A9814FFD9FF673FA Display: "transfer/channel-0/foo", Name: "transfer/channel-0/foo IBC token", Symbol: "FOO", }, { Description: "IBC token from transfer/channel-0/bar", DenomUnits: []*banktypes.DenomUnit{ { Denom: "bar", Exponent: 0, }, }, Base: denomTraces[1].IBCDenom(), // ibc/E1530E21F1848B6C29C9E89256D43E294976897611A61741CACBA55BE21736F5 Display: "transfer/channel-0/bar", Name: "transfer/channel-0/bar IBC token", Symbol: "BAR", }, } // set metadata for one of the tokens, so that it exists already in state before doing the migration suite.chainA.GetSimApp().BankKeeper.SetDenomMetaData(suite.chainA.GetContext(), expectedMetadata[1]) }, }, } for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset ctx := suite.chainA.GetContext() tc.malleate() for _, denomTrace := range denomTraces { suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(ctx, denomTrace) } // run migration migrator := transferkeeper.NewMigrator(suite.chainA.GetSimApp().TransferKeeper) err := migrator.MigrateDenomMetadata(ctx) suite.Require().NoError(err) for _, expMetadata := range expectedMetadata { denomMetadata, found := suite.chainA.GetSimApp().BankKeeper.GetDenomMetaData(ctx, expMetadata.Base) suite.Require().True(found) suite.Require().Equal(expMetadata, denomMetadata) } }) } }