diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 43fae9a3d2b..9ec0430be5f 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -4,6 +4,8 @@ import ( "errors" "math" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,6 +16,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -230,9 +233,11 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { "success", func() {}, nil, }, { - "invalid counterparty version", func() { + "invalid counterparty version", + func() { counterpartyVersion = "version" - }, types.ErrInvalidVersion, + }, + types.ErrInvalidVersion, }, } @@ -268,6 +273,99 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } } +func (suite *TransferTestSuite) TestOnTimeoutPacket() { + var path *ibctesting.Path + var packet channeltypes.Packet + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "non-existent channel", + func() { + packet.SourceChannel = "channel-100" + }, + ibcerrors.ErrNotFound, + }, + { + "invalid packet data", + func() { + packet.Data = []byte("invalid data") + }, + ibcerrors.ErrInvalidType, + }, + { + "already timed-out packet", + func() { + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + suite.Require().NoError(cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress())) + }, + errors.New("unable to unescrow tokens"), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(42)) + timeoutHeight := suite.chainA.GetTimeoutHeight() + msg := types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + sdk.NewCoins(coinToSendToB), + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + timeoutHeight, + 0, + "") + res, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err = ibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + suite.Require().True(ok) + + tc.malleate() // change fields in packet + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) + + expPass := tc.expError == nil + if expPass { + suite.Require().NoError(err) + + escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + escrowBalanceAfter := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom) + suite.Require().Equal(sdkmath.NewInt(0), escrowBalanceAfter.Amount) + } else { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expError.Error()) + } + }) + } +} + func (suite *TransferTestSuite) TestOnChanUpgradeInit() { var path *ibctesting.Path