From eebe2a16f8cd75d9be8650c5237a413aa114aa75 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 26 Oct 2022 15:24:39 +0200 Subject: [PATCH] e2e: adding simd controller msg server tests (#2572) * adding ics27 e2e test for controller msg server * moving legacy tests to separate suite * updating test exclusions * reset number of validators and full nodes * adding simd ica fee test and updating workflows * fix assignment of channelOutput in fee test * fixing typo in workflow yaml * correctly embed the appropriate struct - InterTxTestSuite in incentivized test --- .github/workflows/e2e-manual-icad.yaml | 4 +- .github/workflows/e2e-manual-simd.yaml | 3 + .github/workflows/e2e.yaml | 2 +- e2e/tests/interchain_accounts/base_test.go | 107 +++--- .../interchain_accounts/incentivized_test.go | 82 +++- .../intertx_incentivized_test.go | 355 ++++++++++++++++++ e2e/tests/interchain_accounts/intertx_test.go | 215 +++++++++++ 7 files changed, 692 insertions(+), 76 deletions(-) create mode 100644 e2e/tests/interchain_accounts/intertx_incentivized_test.go create mode 100644 e2e/tests/interchain_accounts/intertx_test.go diff --git a/.github/workflows/e2e-manual-icad.yaml b/.github/workflows/e2e-manual-icad.yaml index 7f6dcb79cbe..1cdb68ccd52 100644 --- a/.github/workflows/e2e-manual-icad.yaml +++ b/.github/workflows/e2e-manual-icad.yaml @@ -10,8 +10,8 @@ on: required: true type: choice options: - - TestInterchainAccountsTestSuite - - TestIncentivizedInterchainAccountsTestSuite + - TestInterTxTestSuite + - TestIncentivizedInterTxTestSuite chain-image: description: 'The image to use for chain A' required: true diff --git a/.github/workflows/e2e-manual-simd.yaml b/.github/workflows/e2e-manual-simd.yaml index f9e1288ba30..ada5abe8ddd 100644 --- a/.github/workflows/e2e-manual-simd.yaml +++ b/.github/workflows/e2e-manual-simd.yaml @@ -12,6 +12,9 @@ on: options: - TestTransferTestSuite - TestIncentivizedTransferTestSuite + - TestInterchainAccountsTestSuite + - TestInterchainAccountsGroupsTestSuite + - TestIncentivizedInterchainAccountsTestSuite chain-image: description: 'The image to use for chain A' required: true diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 4173105392d..28014abf2fa 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -48,4 +48,4 @@ jobs: relayer-tag: "v2.0.0" chain-binary: "simd" # on regular PRs we won't run interchain account or upgrade tests. - test-exclusions: "TestInterchainAccountsTestSuite,TestIncentivizedInterchainAccountsTestSuite,TestUpgradeTestSuite" + test-exclusions: "TestInterTxTestSuite,TestIncentivizedInterTxTestSuite,TestUpgradeTestSuite" diff --git a/e2e/tests/interchain_accounts/base_test.go b/e2e/tests/interchain_accounts/base_test.go index 2ffe6fc10ea..9f51024f0e8 100644 --- a/e2e/tests/interchain_accounts/base_test.go +++ b/e2e/tests/interchain_accounts/base_test.go @@ -3,25 +3,26 @@ package interchain_accounts import ( "context" "testing" + "time" ibctest "github.com/strangelove-ventures/ibctest/v6" - "github.com/strangelove-ventures/ibctest/v6/chain/cosmos" "github.com/strangelove-ventures/ibctest/v6/ibc" "github.com/strangelove-ventures/ibctest/v6/test" "github.com/stretchr/testify/suite" "golang.org/x/mod/semver" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" "github.com/cosmos/ibc-go/e2e/testconfig" "github.com/cosmos/ibc-go/e2e/testsuite" "github.com/cosmos/ibc-go/e2e/testvalues" + controllertypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/types" - feetypes "github.com/cosmos/ibc-go/v6/modules/apps/29-fee/types" ibctesting "github.com/cosmos/ibc-go/v6/testing" + simappparams "github.com/cosmos/ibc-go/v6/testing/simapp/params" ) func TestInterchainAccountsTestSuite(t *testing.T) { @@ -32,22 +33,6 @@ type InterchainAccountsTestSuite struct { testsuite.E2ETestSuite } -// RegisterInterchainAccount will attempt to register an interchain account on the counterparty chain. -func (s *InterchainAccountsTestSuite) RegisterInterchainAccount(ctx context.Context, chain *cosmos.CosmosChain, user *ibc.Wallet, msgRegisterAccount *intertxtypes.MsgRegisterAccount) error { - txResp, err := s.BroadcastMessages(ctx, chain, user, msgRegisterAccount) - s.Require().NoError(err) - s.AssertValidTxResponse(txResp) - return err -} - -// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. -func (s *InterchainAccountsTestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, - user *ibc.Wallet, portID, channelID, relayerAddr, counterpartyPayeeAddr string, -) (sdk.TxResponse, error) { - msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) - return s.BroadcastMessages(ctx, chain, user, msg) -} - // getICAVersion returns the version which should be used in the MsgRegisterAccount broadcast from the // controller chain. func getICAVersion(chainAVersion, chainBVersion string) string { @@ -60,7 +45,7 @@ func getICAVersion(chainAVersion, chainBVersion string) string { return icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) } -func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { +func (s *InterchainAccountsTestSuite) TestMsgSendTx_SuccessfulTransfer() { t := s.T() ctx := context.TODO() @@ -75,11 +60,13 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) var hostAccount string - t.Run("register interchain account", func(t *testing.T) { + t.Run("broadcast MsgRegisterInterchainAccount", func(t *testing.T) { version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) - msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) - err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + msgRegisterAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), version) + + txResp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterAccount) s.Require().NoError(err) + s.AssertValidTxResponse(txResp) }) t.Run("start relayer", func(t *testing.T) { @@ -88,7 +75,7 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { t.Run("verify interchain account", func(t *testing.T) { var err error - hostAccount, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + hostAccount, err = s.QueryInterchainAccount(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) s.Require().NoError(err) s.Require().NotZero(len(hostAccount)) @@ -108,7 +95,7 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { s.Require().NoError(err) }) - t.Run("broadcast MsgSubmitTx", func(t *testing.T) { + t.Run("broadcast MsgSendTx", func(t *testing.T) { // assemble bank transfer message from host account to user account on host chain msgSend := &banktypes.MsgSend{ FromAddress: hostAccount, @@ -116,22 +103,26 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), } - // assemble submitMessage tx for intertx - msgSubmitTx, err := intertxtypes.NewMsgSubmitTx( - msgSend, - ibctesting.FirstConnectionID, - controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), - ) + cfg := simappparams.MakeTestEncodingConfig() + banktypes.RegisterInterfaces(cfg.InterfaceRegistry) + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + + bz, err := icatypes.SerializeCosmosTx(cdc, []sdk.Msg{msgSend}) s.Require().NoError(err) - // broadcast submitMessage tx from controller account on chain A - // this message should trigger the sending of an ICA packet over channel-1 (channel created between controller and host) - // this ICA packet contains the assembled bank transfer message from above, which will be executed by the host account on the host chain. + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "e2e", + } + + msgSendTx := controllertypes.NewMsgSendTx(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, uint64(time.Hour.Nanoseconds()), packetData) + resp, err := s.BroadcastMessages( ctx, chainA, controllerAccount, - msgSubmitTx, + msgSendTx, ) s.AssertValidTxResponse(resp) @@ -153,7 +144,7 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { }) } -func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_FailedTransfer_InsufficientFunds() { +func (s *InterchainAccountsTestSuite) TestMsgSendTx_FailedTransfer_InsufficientFunds() { t := s.T() ctx := context.TODO() @@ -168,11 +159,13 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_FailedTransfer_Insufficien chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) var hostAccount string - t.Run("register interchain account", func(t *testing.T) { + t.Run("broadcast MsgRegisterInterchainAccount", func(t *testing.T) { version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) - msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) - err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + msgRegisterAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), version) + + txResp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterAccount) s.Require().NoError(err) + s.AssertValidTxResponse(txResp) }) t.Run("start relayer", func(t *testing.T) { @@ -181,7 +174,7 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_FailedTransfer_Insufficien t.Run("verify interchain account", func(t *testing.T) { var err error - hostAccount, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + hostAccount, err = s.QueryInterchainAccount(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) s.Require().NoError(err) s.Require().NotZero(len(hostAccount)) @@ -197,34 +190,40 @@ func (s *InterchainAccountsTestSuite) TestMsgSubmitTx_FailedTransfer_Insufficien s.Require().Zero(hostAccountBalance) }) - t.Run("broadcast MsgSubmitTx", func(t *testing.T) { + t.Run("broadcast MsgSendTx", func(t *testing.T) { // assemble bank transfer message from host account to user account on host chain - transferMsg := &banktypes.MsgSend{ + msgSend := &banktypes.MsgSend{ FromAddress: hostAccount, ToAddress: chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), } - // assemble submitMessage tx for intertx - submitMsg, err := intertxtypes.NewMsgSubmitTx( - transferMsg, - ibctesting.FirstConnectionID, - controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), - ) + cfg := simappparams.MakeTestEncodingConfig() + banktypes.RegisterInterfaces(cfg.InterfaceRegistry) + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + + bz, err := icatypes.SerializeCosmosTx(cdc, []sdk.Msg{msgSend}) s.Require().NoError(err) - // broadcast submitMessage tx from controller account on chain A - // this message should trigger the sending of an ICA packet over channel-1 (channel created between controller and host) - // this ICA packet contains the assembled bank transfer message from above, which will be executed by the host account on the host chain. - resp, err := s.BroadcastMessages( + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "e2e", + } + + msgSendTx := controllertypes.NewMsgSendTx(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, uint64(time.Hour.Nanoseconds()), packetData) + + txResp, err := s.BroadcastMessages( ctx, chainA, controllerAccount, - submitMsg, + msgSendTx, ) - s.AssertValidTxResponse(resp) + s.AssertValidTxResponse(txResp) s.Require().NoError(err) + + s.Require().NoError(test.WaitForBlocks(ctx, 10, chainA, chainB)) }) t.Run("verify balance is the same", func(t *testing.T) { diff --git a/e2e/tests/interchain_accounts/incentivized_test.go b/e2e/tests/interchain_accounts/incentivized_test.go index bdcc38a7667..4e5dc67b0f4 100644 --- a/e2e/tests/interchain_accounts/incentivized_test.go +++ b/e2e/tests/interchain_accounts/incentivized_test.go @@ -3,18 +3,24 @@ package interchain_accounts import ( "context" "testing" + "time" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" ibctest "github.com/strangelove-ventures/ibctest/v6" + "github.com/strangelove-ventures/ibctest/v6/chain/cosmos" "github.com/strangelove-ventures/ibctest/v6/ibc" "github.com/strangelove-ventures/ibctest/v6/test" "github.com/stretchr/testify/suite" + "github.com/cosmos/ibc-go/e2e/testconfig" "github.com/cosmos/ibc-go/e2e/testvalues" + controllertypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v6/modules/apps/29-fee/types" ibctesting "github.com/cosmos/ibc-go/v6/testing" + simappparams "github.com/cosmos/ibc-go/v6/testing/simapp/params" ) func TestIncentivizedInterchainAccountsTestSuite(t *testing.T) { @@ -25,7 +31,15 @@ type IncentivizedInterchainAccountsTestSuite struct { InterchainAccountsTestSuite } -func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBankSend_Incentivized() { +// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. +func (s *IncentivizedInterchainAccountsTestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, + user *ibc.Wallet, portID, channelID, relayerAddr, counterpartyPayeeAddr string, +) (sdk.TxResponse, error) { + msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSendTx_SuccessfulBankSend_Incentivized() { t := s.T() ctx := context.TODO() @@ -60,11 +74,13 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - t.Run("register interchain account", func(t *testing.T) { - version := "" // allow app to handle the version as appropriate. - msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) - err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + t.Run("broadcast MsgRegisterInterchainAccount", func(t *testing.T) { + version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) + msgRegisterAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), version) + + txResp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterAccount) s.Require().NoError(err) + s.AssertValidTxResponse(txResp) }) t.Run("start relayer", func(t *testing.T) { @@ -74,7 +90,7 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank var channelOutput ibc.ChannelOutput t.Run("verify interchain account", func(t *testing.T) { var err error - interchainAcc, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + interchainAcc, err = s.QueryInterchainAccount(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) s.Require().NoError(err) s.Require().NotZero(len(interchainAcc)) @@ -84,6 +100,8 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank // interchain accounts channel at index: 0 channelOutput = channels[0] + + s.Require().NoError(test.WaitForBlocks(ctx, 2, chainA, chainB)) }) t.Run("execute interchain account bank send through controller", func(t *testing.T) { @@ -119,7 +137,7 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank s.StopRelayer(ctx, relayer) }) - t.Run("broadcast incentivized MsgSubmitTx", func(t *testing.T) { + t.Run("broadcast incentivized MsgSendTx", func(t *testing.T) { msgPayPacketFee := &feetypes.MsgPayPacketFee{ Fee: testvalues.DefaultFee(chainADenom), SourcePortId: channelOutput.PortID, @@ -133,10 +151,22 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), } - msgSubmitTx, err := intertxtypes.NewMsgSubmitTx(msgSend, ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix)) + cfg := simappparams.MakeTestEncodingConfig() + banktypes.RegisterInterfaces(cfg.InterfaceRegistry) + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + + bz, err := icatypes.SerializeCosmosTx(cdc, []sdk.Msg{msgSend}) s.Require().NoError(err) - resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSubmitTx) + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "e2e", + } + + msgSendTx := controllertypes.NewMsgSendTx(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, uint64(time.Hour.Nanoseconds()), packetData) + + resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSendTx) s.AssertValidTxResponse(resp) s.Require().NoError(err) @@ -193,7 +223,7 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_SuccessfulBank }) } -func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_FailedBankSend_Incentivized() { +func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSendTx_FailedBankSend_Incentivized() { t := s.T() ctx := context.TODO() @@ -228,11 +258,13 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_FailedBankSend controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - t.Run("register interchain account", func(t *testing.T) { - version := "" // allow app to handle the version as appropriate. - msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) - err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + t.Run("broadcast MsgRegisterInterchainAccount", func(t *testing.T) { + version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) + msgRegisterAccount := controllertypes.NewMsgRegisterInterchainAccount(ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), version) + + txResp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgRegisterAccount) s.Require().NoError(err) + s.AssertValidTxResponse(txResp) }) t.Run("start relayer", func(t *testing.T) { @@ -242,7 +274,7 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_FailedBankSend var channelOutput ibc.ChannelOutput t.Run("verify interchain account", func(t *testing.T) { var err error - interchainAcc, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + interchainAcc, err = s.QueryInterchainAccount(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) s.Require().NoError(err) s.Require().NotZero(len(interchainAcc)) @@ -280,7 +312,7 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_FailedBankSend s.Require().NoError(err) }) - t.Run("broadcast incentivized MsgSubmitTx", func(t *testing.T) { + t.Run("broadcast incentivized MsgSendTx", func(t *testing.T) { msgPayPacketFee := &feetypes.MsgPayPacketFee{ Fee: testvalues.DefaultFee(chainADenom), SourcePortId: channelOutput.PortID, @@ -294,10 +326,22 @@ func (s *IncentivizedInterchainAccountsTestSuite) TestMsgSubmitTx_FailedBankSend Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), } - msgSubmitTx, err := intertxtypes.NewMsgSubmitTx(msgSend, ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix)) + cfg := simappparams.MakeTestEncodingConfig() + banktypes.RegisterInterfaces(cfg.InterfaceRegistry) + cdc := codec.NewProtoCodec(cfg.InterfaceRegistry) + + bz, err := icatypes.SerializeCosmosTx(cdc, []sdk.Msg{msgSend}) s.Require().NoError(err) - resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSubmitTx) + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: bz, + Memo: "e2e", + } + + msgSendTx := controllertypes.NewMsgSendTx(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, uint64(time.Hour.Nanoseconds()), packetData) + + resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSendTx) s.AssertValidTxResponse(resp) s.Require().NoError(err) diff --git a/e2e/tests/interchain_accounts/intertx_incentivized_test.go b/e2e/tests/interchain_accounts/intertx_incentivized_test.go new file mode 100644 index 00000000000..063c3f30be6 --- /dev/null +++ b/e2e/tests/interchain_accounts/intertx_incentivized_test.go @@ -0,0 +1,355 @@ +package interchain_accounts + +import ( + "context" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" + ibctest "github.com/strangelove-ventures/ibctest/v6" + "github.com/strangelove-ventures/ibctest/v6/ibc" + "github.com/strangelove-ventures/ibctest/v6/test" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/e2e/testvalues" + feetypes "github.com/cosmos/ibc-go/v6/modules/apps/29-fee/types" + ibctesting "github.com/cosmos/ibc-go/v6/testing" +) + +func TestIncentivizedInterTxTestSuite(t *testing.T) { + suite.Run(t, new(IncentivizedInterTxTestSuite)) +} + +type IncentivizedInterTxTestSuite struct { + InterTxTestSuite +} + +func (s *IncentivizedInterTxTestSuite) TestMsgSubmitTx_SuccessfulBankSend_Incentivized() { + t := s.T() + ctx := context.TODO() + + // setup relayers and connection-0 between two chains + // channel-0 is a transfer channel but it will not be used in this test case + relayer, _ := s.SetupChainsRelayerAndChannel(ctx) + chainA, chainB := s.GetChains() + + var ( + chainADenom = chainA.Config().Denom + interchainAcc = "" + testFee = testvalues.DefaultFee(chainADenom) + ) + + t.Run("relayer wallets recovered", func(t *testing.T) { + err := s.RecoverRelayerWallets(ctx, relayer) + s.Require().NoError(err) + }) + + chainARelayerWallet, chainBRelayerWallet, err := s.GetRelayerWallets(relayer) + t.Run("relayer wallets fetched", func(t *testing.T) { + s.Require().NoError(err) + }) + + s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks") + + chainARelayerUser, chainBRelayerUser := s.GetRelayerUsers(ctx) + relayerAStartingBalance, err := s.GetChainANativeBalance(ctx, chainARelayerUser) + s.Require().NoError(err) + t.Logf("relayer A user starting with balance: %d", relayerAStartingBalance) + + controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + + t.Run("register interchain account", func(t *testing.T) { + version := "" // allow app to handle the version as appropriate. + msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) + err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + s.Require().NoError(err) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + var channelOutput ibc.ChannelOutput + t.Run("verify interchain account", func(t *testing.T) { + var err error + interchainAcc, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + s.Require().NoError(err) + s.Require().NotZero(len(interchainAcc)) + + channels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) + s.Require().NoError(err) + s.Require().Equal(len(channels), 2) + + // interchain accounts channel at index: 0 + channelOutput = channels[0] + }) + + t.Run("execute interchain account bank send through controller", func(t *testing.T) { + t.Run("fund interchain account wallet on host chainB", func(t *testing.T) { + // fund the interchain account so it has some $$ to send + err := chainB.SendFunds(ctx, ibctest.FaucetAccountKeyName, ibc.WalletAmount{ + Address: interchainAcc, + Amount: testvalues.StartingTokenAmount, + Denom: chainB.Config().Denom, + }) + s.Require().NoError(err) + }) + + t.Run("register counterparty payee", func(t *testing.T) { + resp, err := s.RegisterCounterPartyPayee(ctx, chainB, chainBRelayerUser, channelOutput.Counterparty.PortID, channelOutput.Counterparty.ChannelID, chainBRelayerWallet.Address, chainARelayerWallet.Address) + s.Require().NoError(err) + s.AssertValidTxResponse(resp) + }) + + t.Run("verify counterparty payee", func(t *testing.T) { + address, err := s.QueryCounterPartyPayee(ctx, chainB, chainBRelayerWallet.Address, channelOutput.Counterparty.ChannelID) + s.Require().NoError(err) + s.Require().Equal(chainARelayerWallet.Address, address) + }) + + t.Run("no incentivized packets", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Empty(packets) + }) + + t.Run("stop relayer", func(t *testing.T) { + s.StopRelayer(ctx, relayer) + }) + + t.Run("broadcast incentivized MsgSubmitTx", func(t *testing.T) { + msgPayPacketFee := &feetypes.MsgPayPacketFee{ + Fee: testvalues.DefaultFee(chainADenom), + SourcePortId: channelOutput.PortID, + SourceChannelId: channelOutput.ChannelID, + Signer: controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), + } + + msgSend := &banktypes.MsgSend{ + FromAddress: interchainAcc, + ToAddress: chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), + Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), + } + + msgSubmitTx, err := intertxtypes.NewMsgSubmitTx(msgSend, ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix)) + s.Require().NoError(err) + + resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSubmitTx) + s.AssertValidTxResponse(resp) + s.Require().NoError(err) + + s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB)) + }) + + t.Run("there should be incentivized packets", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Len(packets, 1) + actualFee := packets[0].PacketFees[0].Fee + + s.Require().True(actualFee.RecvFee.IsEqual(testFee.RecvFee)) + s.Require().True(actualFee.AckFee.IsEqual(testFee.AckFee)) + s.Require().True(actualFee.TimeoutFee.IsEqual(testFee.TimeoutFee)) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("packets are relayed", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Empty(packets) + }) + + t.Run("verify interchain account sent tokens", func(t *testing.T) { + balance, err := chainB.GetBalance(ctx, chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), chainB.Config().Denom) + s.Require().NoError(err) + + _, err = chainB.GetBalance(ctx, interchainAcc, chainB.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.IBCTransferAmount + testvalues.StartingTokenAmount + s.Require().Equal(expected, balance) + }) + + t.Run("timeout fee is refunded", func(t *testing.T) { + actualBalance, err := s.GetChainANativeBalance(ctx, controllerAccount) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount - testFee.AckFee.AmountOf(chainADenom).Int64() - testFee.RecvFee.AmountOf(chainADenom).Int64() + s.Require().Equal(expected, actualBalance) + }) + + t.Run("relayerA is paid ack and recv fee", func(t *testing.T) { + actualBalance, err := s.GetChainANativeBalance(ctx, chainARelayerUser) + s.Require().NoError(err) + + expected := relayerAStartingBalance + testFee.AckFee.AmountOf(chainADenom).Int64() + testFee.RecvFee.AmountOf(chainADenom).Int64() + s.Require().Equal(expected, actualBalance) + }) + }) +} + +func (s *IncentivizedInterTxTestSuite) TestMsgSubmitTx_FailedBankSend_Incentivized() { + t := s.T() + ctx := context.TODO() + + // setup relayers and connection-0 between two chains + // channel-0 is a transfer channel but it will not be used in this test case + relayer, _ := s.SetupChainsRelayerAndChannel(ctx) + chainA, chainB := s.GetChains() + + var ( + chainADenom = chainA.Config().Denom + interchainAcc = "" + testFee = testvalues.DefaultFee(chainADenom) + ) + + t.Run("relayer wallets recovered", func(t *testing.T) { + err := s.RecoverRelayerWallets(ctx, relayer) + s.Require().NoError(err) + }) + + chainARelayerWallet, chainBRelayerWallet, err := s.GetRelayerWallets(relayer) + t.Run("relayer wallets fetched", func(t *testing.T) { + s.Require().NoError(err) + }) + + s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks") + + chainARelayerUser, chainBRelayerUser := s.GetRelayerUsers(ctx) + relayerAStartingBalance, err := s.GetChainANativeBalance(ctx, chainARelayerUser) + s.Require().NoError(err) + t.Logf("relayer A user starting with balance: %d", relayerAStartingBalance) + + controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + + t.Run("register interchain account", func(t *testing.T) { + version := "" // allow app to handle the version as appropriate. + msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) + err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + s.Require().NoError(err) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + var channelOutput ibc.ChannelOutput + t.Run("verify interchain account", func(t *testing.T) { + var err error + interchainAcc, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + s.Require().NoError(err) + s.Require().NotZero(len(interchainAcc)) + + channels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) + s.Require().NoError(err) + s.Require().Equal(len(channels), 2) + + // interchain accounts channel at index: 0 + channelOutput = channels[0] + + s.Require().NoError(test.WaitForBlocks(ctx, 2, chainA, chainB)) + }) + + t.Run("execute interchain account bank send through controller", func(t *testing.T) { + t.Run("register counterparty payee", func(t *testing.T) { + resp, err := s.RegisterCounterPartyPayee(ctx, chainB, chainBRelayerUser, channelOutput.Counterparty.PortID, channelOutput.Counterparty.ChannelID, chainBRelayerWallet.Address, chainARelayerWallet.Address) + s.Require().NoError(err) + s.AssertValidTxResponse(resp) + }) + + t.Run("verify counterparty payee", func(t *testing.T) { + address, err := s.QueryCounterPartyPayee(ctx, chainB, chainBRelayerWallet.Address, channelOutput.Counterparty.ChannelID) + s.Require().NoError(err) + s.Require().Equal(chainARelayerWallet.Address, address) + }) + + t.Run("no incentivized packets", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Empty(packets) + }) + + t.Run("stop relayer", func(t *testing.T) { + err := relayer.StopRelayer(ctx, s.GetRelayerExecReporter()) + s.Require().NoError(err) + }) + + t.Run("broadcast incentivized MsgSubmitTx", func(t *testing.T) { + msgPayPacketFee := &feetypes.MsgPayPacketFee{ + Fee: testvalues.DefaultFee(chainADenom), + SourcePortId: channelOutput.PortID, + SourceChannelId: channelOutput.ChannelID, + Signer: controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), + } + + msgSend := &banktypes.MsgSend{ + FromAddress: interchainAcc, + ToAddress: chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), + Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), + } + + msgSubmitTx, err := intertxtypes.NewMsgSubmitTx(msgSend, ibctesting.FirstConnectionID, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix)) + s.Require().NoError(err) + + resp, err := s.BroadcastMessages(ctx, chainA, controllerAccount, msgPayPacketFee, msgSubmitTx) + s.AssertValidTxResponse(resp) + s.Require().NoError(err) + + s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB)) + }) + + t.Run("there should be incentivized packets", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Len(packets, 1) + actualFee := packets[0].PacketFees[0].Fee + + s.Require().True(actualFee.RecvFee.IsEqual(testFee.RecvFee)) + s.Require().True(actualFee.AckFee.IsEqual(testFee.AckFee)) + s.Require().True(actualFee.TimeoutFee.IsEqual(testFee.TimeoutFee)) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("packets are relayed", func(t *testing.T) { + packets, err := s.QueryIncentivizedPacketsForChannel(ctx, chainA, channelOutput.PortID, channelOutput.ChannelID) + s.Require().NoError(err) + s.Require().Empty(packets) + }) + + t.Run("verify interchain account did not send tokens", func(t *testing.T) { + balance, err := chainB.GetBalance(ctx, chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), chainB.Config().Denom) + s.Require().NoError(err) + + _, err = chainB.GetBalance(ctx, interchainAcc, chainB.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount + s.Require().Equal(expected, balance, "tokens should not have been sent as interchain account was not funded") + }) + + t.Run("timeout fee is refunded", func(t *testing.T) { + actualBalance, err := s.GetChainANativeBalance(ctx, controllerAccount) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount - testFee.AckFee.AmountOf(chainADenom).Int64() - testFee.RecvFee.AmountOf(chainADenom).Int64() + s.Require().Equal(expected, actualBalance) + }) + + t.Run("relayerA is paid ack and recv fee", func(t *testing.T) { + actualBalance, err := s.GetChainANativeBalance(ctx, chainARelayerUser) + s.Require().NoError(err) + + expected := relayerAStartingBalance + testFee.AckFee.AmountOf(chainADenom).Int64() + testFee.RecvFee.AmountOf(chainADenom).Int64() + s.Require().Equal(expected, actualBalance) + }) + }) +} diff --git a/e2e/tests/interchain_accounts/intertx_test.go b/e2e/tests/interchain_accounts/intertx_test.go new file mode 100644 index 00000000000..8340b2ed8a8 --- /dev/null +++ b/e2e/tests/interchain_accounts/intertx_test.go @@ -0,0 +1,215 @@ +package interchain_accounts + +import ( + "context" + "testing" + + ibctest "github.com/strangelove-ventures/ibctest/v6" + "github.com/strangelove-ventures/ibctest/v6/chain/cosmos" + "github.com/strangelove-ventures/ibctest/v6/ibc" + "github.com/strangelove-ventures/ibctest/v6/test" + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" + + "github.com/cosmos/ibc-go/e2e/testconfig" + "github.com/cosmos/ibc-go/e2e/testsuite" + "github.com/cosmos/ibc-go/e2e/testvalues" + + ibctesting "github.com/cosmos/ibc-go/v6/testing" +) + +func TestInterTxTestSuite(t *testing.T) { + suite.Run(t, new(InterTxTestSuite)) +} + +type InterTxTestSuite struct { + testsuite.E2ETestSuite +} + +// RegisterInterchainAccount will attempt to register an interchain account on the counterparty chain. +func (s *InterTxTestSuite) RegisterInterchainAccount(ctx context.Context, chain *cosmos.CosmosChain, user *ibc.Wallet, msgRegisterAccount *intertxtypes.MsgRegisterAccount) error { + txResp, err := s.BroadcastMessages(ctx, chain, user, msgRegisterAccount) + s.Require().NoError(err) + s.AssertValidTxResponse(txResp) + return err +} + +func (s *InterTxTestSuite) TestMsgSubmitTx_SuccessfulTransfer() { + t := s.T() + ctx := context.TODO() + + // setup relayers and connection-0 between two chains + // channel-0 is a transfer channel but it will not be used in this test case + relayer, _ := s.SetupChainsRelayerAndChannel(ctx) + chainA, chainB := s.GetChains() + + // setup 2 accounts: controller account on chain A, a second chain B account. + // host account will be created when the ICA is registered + controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + var hostAccount string + + t.Run("register interchain account", func(t *testing.T) { + version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) + msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) + err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + s.Require().NoError(err) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("verify interchain account", func(t *testing.T) { + var err error + hostAccount, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + s.Require().NoError(err) + s.Require().NotZero(len(hostAccount)) + + channels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) + s.Require().NoError(err) + s.Require().Equal(len(channels), 2) + }) + + t.Run("interchain account executes a bank transfer on behalf of the corresponding owner account", func(t *testing.T) { + t.Run("fund interchain account wallet", func(t *testing.T) { + // fund the host account account so it has some $$ to send + err := chainB.SendFunds(ctx, ibctest.FaucetAccountKeyName, ibc.WalletAmount{ + Address: hostAccount, + Amount: testvalues.StartingTokenAmount, + Denom: chainB.Config().Denom, + }) + s.Require().NoError(err) + }) + + t.Run("broadcast MsgSubmitTx", func(t *testing.T) { + // assemble bank transfer message from host account to user account on host chain + msgSend := &banktypes.MsgSend{ + FromAddress: hostAccount, + ToAddress: chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), + Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), + } + + // assemble submitMessage tx for intertx + msgSubmitTx, err := intertxtypes.NewMsgSubmitTx( + msgSend, + ibctesting.FirstConnectionID, + controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), + ) + s.Require().NoError(err) + + // broadcast submitMessage tx from controller account on chain A + // this message should trigger the sending of an ICA packet over channel-1 (channel created between controller and host) + // this ICA packet contains the assembled bank transfer message from above, which will be executed by the host account on the host chain. + resp, err := s.BroadcastMessages( + ctx, + chainA, + controllerAccount, + msgSubmitTx, + ) + + s.AssertValidTxResponse(resp) + s.Require().NoError(err) + + s.Require().NoError(test.WaitForBlocks(ctx, 10, chainA, chainB)) + }) + + t.Run("verify tokens transferred", func(t *testing.T) { + balance, err := chainB.GetBalance(ctx, chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), chainB.Config().Denom) + s.Require().NoError(err) + + _, err = chainB.GetBalance(ctx, hostAccount, chainB.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.IBCTransferAmount + testvalues.StartingTokenAmount + s.Require().Equal(expected, balance) + }) + }) +} + +func (s *InterTxTestSuite) TestMsgSubmitTx_FailedTransfer_InsufficientFunds() { + t := s.T() + ctx := context.TODO() + + // setup relayers and connection-0 between two chains + // channel-0 is a transfer channel but it will not be used in this test case + relayer, _ := s.SetupChainsRelayerAndChannel(ctx) + chainA, chainB := s.GetChains() + + // setup 2 accounts: controller account on chain A, a second chain B account. + // host account will be created when the ICA is registered + controllerAccount := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + chainBAccount := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) + var hostAccount string + + t.Run("register interchain account", func(t *testing.T) { + version := getICAVersion(testconfig.GetChainATag(), testconfig.GetChainBTag()) + msgRegisterAccount := intertxtypes.NewMsgRegisterAccount(controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID, version) + err := s.RegisterInterchainAccount(ctx, chainA, controllerAccount, msgRegisterAccount) + s.Require().NoError(err) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("verify interchain account", func(t *testing.T) { + var err error + hostAccount, err = s.QueryInterchainAccountLegacy(ctx, chainA, controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), ibctesting.FirstConnectionID) + s.Require().NoError(err) + s.Require().NotZero(len(hostAccount)) + + channels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) + s.Require().NoError(err) + s.Require().Equal(len(channels), 2) + }) + + t.Run("fail to execute bank transfer over ICA", func(t *testing.T) { + t.Run("verify empty host wallet", func(t *testing.T) { + hostAccountBalance, err := chainB.GetBalance(ctx, hostAccount, chainB.Config().Denom) + s.Require().NoError(err) + s.Require().Zero(hostAccountBalance) + }) + + t.Run("broadcast MsgSubmitTx", func(t *testing.T) { + // assemble bank transfer message from host account to user account on host chain + transferMsg := &banktypes.MsgSend{ + FromAddress: hostAccount, + ToAddress: chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), + Amount: sdk.NewCoins(testvalues.DefaultTransferAmount(chainB.Config().Denom)), + } + + // assemble submitMessage tx for intertx + submitMsg, err := intertxtypes.NewMsgSubmitTx( + transferMsg, + ibctesting.FirstConnectionID, + controllerAccount.Bech32Address(chainA.Config().Bech32Prefix), + ) + s.Require().NoError(err) + + // broadcast submitMessage tx from controller account on chain A + // this message should trigger the sending of an ICA packet over channel-1 (channel created between controller and host) + // this ICA packet contains the assembled bank transfer message from above, which will be executed by the host account on the host chain. + resp, err := s.BroadcastMessages( + ctx, + chainA, + controllerAccount, + submitMsg, + ) + + s.AssertValidTxResponse(resp) + s.Require().NoError(err) + }) + + t.Run("verify balance is the same", func(t *testing.T) { + balance, err := chainB.GetBalance(ctx, chainBAccount.Bech32Address(chainB.Config().Bech32Prefix), chainB.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount + s.Require().Equal(expected, balance) + }) + }) +}