diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 74051f3942a..98a31b79918 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -1007,7 +1007,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketDataV1() { Tokens: []transfertypes.Token{ { Denom: transfertypes.Denom{ - Base: ibctesting.TestCoin.Denom, + Base: ibctesting.TestCoin.GetDenom(), Trace: nil, }, Amount: ibctesting.TestCoin.Amount.String(), @@ -1043,7 +1043,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketDataV2() { Tokens: []transfertypes.Token{ { Denom: transfertypes.Denom{ - Base: ibctesting.TestCoin.Denom, + Base: ibctesting.TestCoin.GetDenom(), Trace: nil, }, Amount: ibctesting.TestCoin.Amount.String(), diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index be4098f9bc9..be01f892189 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -13,6 +13,7 @@ import ( transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) @@ -250,6 +251,287 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { types.CallbackData{}, types.ErrCallbackAddressNotFound, }, + + { + "success: source callback", + func() { + remainingGas = 2_000_000 + packetData = transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "success: destination callback", + func() { + callbackKey = types.DestinationCallbackKey + + remainingGas = 2_000_000 + packetData = transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "success v2: destination callback with 0 user defined gas limit", + func() { + callbackKey = types.DestinationCallbackKey + + remainingGas = 2_000_000 + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit":"0"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "success v2: source callback with gas limit < remaining gas < max gas", + func() { + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), + } + + remainingGas = 100_000 + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 50_000, + CommitGasLimit: 50_000, + }, + nil, + }, + { + "success v2: source callback with remaining gas < gas limit < max gas", + func() { + remainingGas = 100_000 + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 100_000, + CommitGasLimit: 200_000, + }, + nil, + }, + { + "success v2: source callback with remaining gas < max gas < gas limit", + func() { + remainingGas = 100_000 + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 100_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "success v2: destination callback with remaining gas < max gas < gas limit", + func() { + callbackKey = types.DestinationCallbackKey + + remainingGas = 100_000 + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 100_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "success v2: source callback with max gas < remaining gas < gas limit", + func() { + remainingGas = 2_000_000 + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), + } + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + nil, + }, + { + "failure: packet data does not implement PacketDataProvider", + func() { + packetData = ibcmock.MockPacketData + }, + types.CallbackData{}, + types.ErrNotPacketDataProvider, + }, + { + "failure v2: empty memo", + func() { + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "", + } + }, + types.CallbackData{}, + types.ErrCallbackKeyNotFound, + }, + { + "failure v2: empty address", + func() { + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": ""}}`, + } + }, + types.CallbackData{}, + types.ErrCallbackAddressNotFound, + }, + { + "failure v2: space address", + func() { + packetData = transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": " "}}`, + } + }, + types.CallbackData{}, + types.ErrCallbackAddressNotFound, + }, } for _, tc := range testCases { @@ -277,109 +559,206 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { } } -func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { - s.SetupTest() +// bytesProvider defines an interface that both packet data types implement in order to fetch the bytes. +type bytesProvider interface { + GetBytes() []byte +} +func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - packetData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + testCases := []struct { + name string + packetData bytesProvider + expCallbackData types.CallbackData + malleate func() + }{ + { + "success: v1", + transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + func() { + s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + }, + }, + { + "success: v2", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: sender, + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + func() { + s.path.EndpointA.ChannelConfig.Version = transfertypes.V2 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V2 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + }, + }, } - packetDataBytes := packetData.GetBytes() - expCallbackData := types.CallbackData{ - CallbackAddress: sender, - SenderAddress: sender, - ExecutionGasLimit: 1_000_000, - CommitGasLimit: 1_000_000, - } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTest() - s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 - s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName - s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 - s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + tc.malleate() - transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) - s.Require().True(ok) + packetDataBytes := tc.packetData.GetBytes() - packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) - s.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + s.Require().True(ok) - s.path.Setup() + packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) + s.Require().True(ok) - // Set up gas meter for context. - gasMeter := storetypes.NewGasMeter(2_000_000) - ctx := s.chainA.GetContext().WithGasMeter(gasMeter) + s.path.Setup() - packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) - callbackData, err := types.GetSourceCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) - s.Require().NoError(err) - s.Require().Equal(expCallbackData, callbackData) + gasMeter := storetypes.NewGasMeter(2_000_000) + ctx := s.chainA.GetContext().WithGasMeter(gasMeter) + packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) + callbackData, err := types.GetSourceCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) + s.Require().NoError(err) + s.Require().Equal(tc.expCallbackData, callbackData) + }) + } } func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { - s.SetupTest() - sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - packetData := transfertypes.FungibleTokenPacketData{ - Denom: ibctesting.TestCoin.Denom, - Amount: ibctesting.TestCoin.Amount.String(), - Sender: sender, - Receiver: receiver, - Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + testCases := []struct { + name string + packetData bytesProvider + expCallbackdata types.CallbackData + malleate func() + }{ + { + "success: v1", + transfertypes.FungibleTokenPacketData{ + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + func() { + s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + }, + }, + { + "success: v2", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + }, + Amount: ibctesting.TestCoin.Amount.String(), + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), + }, + types.CallbackData{ + CallbackAddress: sender, + SenderAddress: "", + ExecutionGasLimit: 1_000_000, + CommitGasLimit: 1_000_000, + }, + func() { + s.path.EndpointA.ChannelConfig.Version = transfertypes.V2 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V2 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + }, + }, } - packetDataBytes := packetData.GetBytes() - expCallbackData := types.CallbackData{ - CallbackAddress: sender, - SenderAddress: "", - ExecutionGasLimit: 1_000_000, - CommitGasLimit: 1_000_000, - } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + s.SetupTest() - s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 - s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName - s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 - s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + tc.malleate() + + packetDataBytes := tc.packetData.GetBytes() - transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) - s.Require().True(ok) + transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + s.Require().True(ok) - packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) - s.Require().True(ok) + packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) + s.Require().True(ok) - s.path.Setup() + s.path.Setup() - gasMeter := storetypes.NewGasMeter(2_000_000) - ctx := s.chainA.GetContext().WithGasMeter(gasMeter) - packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) - callbackData, err := types.GetDestCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) - s.Require().NoError(err) - s.Require().Equal(expCallbackData, callbackData) + gasMeter := storetypes.NewGasMeter(2_000_000) + ctx := s.chainA.GetContext().WithGasMeter(gasMeter) + packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) + callbackData, err := types.GetDestCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) + s.Require().NoError(err) + s.Require().Equal(tc.expCallbackdata, callbackData) + }) + } } func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { - denom := ibctesting.TestCoin.Denom + denom := transfertypes.Denom{Base: ibctesting.TestCoin.Denom} amount := ibctesting.TestCoin.Amount.String() sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() testCases := []struct { name string - packetData transfertypes.FungibleTokenPacketData + packetData ibcexported.PacketDataProvider expAddress string }{ { "success: memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -390,7 +769,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "success: valid src_callback address specified in memo that matches sender", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -401,7 +780,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo is empty", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -412,7 +791,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo is not json string", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -423,7 +802,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo has empty src_callback object", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -434,7 +813,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo does not have callbacks in json struct", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -445,7 +824,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo has src_callback in json struct but does not have address key", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -456,7 +835,7 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { { "failure: memo has src_callback in json struct but does not have string value for address key", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -464,6 +843,126 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { }, "", }, + { + "success v2: memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), + }, + receiver, + }, + { + "success v2: valid src_callback address specified in memo that matches sender", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), + }, + sender, + }, + { + "failure v2: memo is empty", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + "", + }, + { + "failure v2: memo is not json string", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "memo", + }, + "", + }, + { + "failure v2: memo has empty src_callback object", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {}}`, + }, + "", + }, + { + "failure v2: memo does not have callbacks in json struct", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"Key": 10}`, + }, + "", + }, + { + "failure v2: memo has src_callback in json struct but does not have address key", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"Key": 10}}`, + }, + "", + }, + { + "failure v2: memo has src_callback in json struct but does not have string value for address key", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"address": 10}}`, + }, + "", + }, } for _, tc := range testCases { @@ -477,20 +976,23 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackAddress() { } func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { - denom := ibctesting.TestCoin.Denom + denom := transfertypes.Denom{ + Base: ibctesting.TestCoin.Denom, + Trace: nil, + } amount := ibctesting.TestCoin.Amount.String() sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() testCases := []struct { name string - packetData transfertypes.FungibleTokenPacketData + packetData ibcexported.PacketDataProvider expUserGas uint64 }{ { "success: memo is empty", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -501,7 +1003,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "success: memo has user defined gas limit", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -512,7 +1014,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "success: user defined gas limit is zero", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -523,7 +1025,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: memo has empty src_callback object", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -534,7 +1036,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: memo has user defined gas limit as json number", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -545,7 +1047,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: memo has user defined gas limit as negative", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -556,7 +1058,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: memo has user defined gas limit as string", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -567,7 +1069,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: memo has user defined gas limit as empty string", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -578,7 +1080,7 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { { "failure: malformed memo", transfertypes.FungibleTokenPacketData{ - Denom: denom, + Denom: denom.Base, Amount: amount, Sender: sender, Receiver: receiver, @@ -586,6 +1088,141 @@ func (s *CallbacksTypesTestSuite) TestUserDefinedGasLimit() { }, 0, }, + { + "success v2: memo is empty", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "", + }, + 0, + }, + { + "success v2: memo has user defined gas limit", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "100"}}`, + }, + 100, + }, + { + "success v2: user defined gas limit is zero", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "0"}}`, + }, + 0, + }, + { + "failure v2: memo has empty src_callback object", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {}}`, + }, + 0, + }, + { + "failure v2: memo has user defined gas limit as json number", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": 100}}`, + }, + 0, + }, + { + "failure v2: memo has user defined gas limit as negative", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "-100"}}`, + }, + 0, + }, + { + "failure v2: memo has user defined gas limit as string", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": "invalid"}}`, + }, + 0, + }, + { + "failure v2: memo has user defined gas limit as empty string", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `{"src_callback": {"gas_limit": ""}}`, + }, + 0, + }, + { + "failure v2: malformed memo", + transfertypes.FungibleTokenPacketDataV2{ + Tokens: transfertypes.Tokens{ + { + Denom: denom, + Amount: amount, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: `invalid`, + }, + 0, + }, } for _, tc := range testCases {