From bf93c0e458477b07875bd5e649d7620ca49e56d3 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 13 Mar 2023 18:58:28 +0100 Subject: [PATCH 01/10] adr 8 with 20/27 implementation --- .../27-interchain-accounts/types/packet.go | 52 +++++++++++++++++ modules/apps/transfer/types/packet.go | 56 +++++++++++++++++++ modules/core/exported/callbacks.go | 19 +++++++ 3 files changed, 127 insertions(+) create mode 100644 modules/core/exported/callbacks.go diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index f7d1c6648be..7baa37cfaf7 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "time" errorsmod "cosmossdk.io/errors" @@ -47,6 +48,57 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } +// ADR-8 middleware should callback on the sender address on the source chain +// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() (addr string) { + if len(iapd.Memo) == 0 { + return + } + + jsonObject := make(map[string]interface{}) + // the jsonObject must be a valid JSON object + err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) + if err != nil { + return + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return + } + + callbackAddr := callbackData["src_callback_address"].(string) + return callbackAddr +} + +// ADR-8 middleware should callback on the receiver address on the destination chain +// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +func (iapd InterchainAccountPacketData) GetDestCallbackAddress() (addr string) { + if len(iapd.Memo) == 0 { + return + } + + jsonObject := make(map[string]interface{}) + // the jsonObject must be a valid JSON object + err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) + if err != nil { + return + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return + } + + callbackAddr := callbackData["dest_callback_address"].(string) + return callbackAddr +} + +// no-op on this method to use relayer passed in gas +func (fptd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { + return 0 +} + // GetBytes returns the JSON marshalled interchain account CosmosTx. func (ct CosmosTx) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&ct)) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index ec795fa2482..0ba9d4e2835 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -1,6 +1,7 @@ package types import ( + "encoding/json" "strings" "time" @@ -62,3 +63,58 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } + +// ADR-8 middleware should callback on the sender address on the source chain +// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() (addr string) { + if len(ftpd.Memo) == 0 { + return + } + + jsonObject := make(map[string]interface{}) + // the jsonObject must be a valid JSON object + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return + } + + if callbackData["src_callback_address"] == ftpd.Sender { + return ftpd.Sender + } + return +} + +// ADR-8 middleware should callback on the receiver address on the destination chain +// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() (addr string) { + if len(ftpd.Memo) == 0 { + return + } + + jsonObject := make(map[string]interface{}) + // the jsonObject must be a valid JSON object + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return + } + + callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) + if !ok { + return + } + + if callbackData["dest_callback_address"] == ftpd.Receiver { + return ftpd.Receiver + } + return +} + +// no-op on this method to use relayer passed in gas +func (fptd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { + return 0 +} diff --git a/modules/core/exported/callbacks.go b/modules/core/exported/callbacks.go new file mode 100644 index 00000000000..a177d9f0bd1 --- /dev/null +++ b/modules/core/exported/callbacks.go @@ -0,0 +1,19 @@ +package exported + +type CallbackPacketData interface { + // may return the empty string + GetSrcCallbackAddress() string + + // may return the empty string + GetDestCallbackAddress() string + + // UserDefinedGasLimit allows the sender of the packet to define inside the packet data + // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed + // in as the gas limit so that the callback is guaranteed to complete within a specific limit. + // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. + // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still + // commit the transaction. This ensures the packet lifecycle can always complete. + // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) + // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + UserDefinedGasLimit() uint64 +} From 8c16e8d941024950f2393be71534fbaf76609db4 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 13 Mar 2023 19:08:53 +0100 Subject: [PATCH 02/10] change interface name and register codecs --- modules/apps/27-interchain-accounts/types/codec.go | 6 ++++++ modules/apps/27-interchain-accounts/types/packet.go | 3 +++ modules/apps/transfer/types/codec.go | 6 ++++++ modules/apps/transfer/types/packet.go | 3 +++ modules/core/exported/callbacks.go | 2 +- modules/core/exported/codec.go | 12 ++++++++++++ modules/core/types/codec.go | 2 ++ 7 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 modules/core/exported/codec.go diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index b0ba7b8902b..87436519415 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // ModuleCdc references the global interchain accounts module codec. Note, the codec @@ -21,6 +22,11 @@ var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) registry.RegisterImplementations((*authtypes.GenesisAccount)(nil), &InterchainAccount{}) + + registry.RegisterImplementations( + (*exported.CallbackPacketDataI)(nil), + &InterchainAccountPacketData{}, + ) } // SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 7baa37cfaf7..25d032a7be5 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -7,6 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // MaxMemoCharLength defines the maximum length for the InterchainAccountPacketData memo field @@ -25,6 +26,8 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) +var _ exported.CallbackPacketDataI = (*InterchainAccountPacketData)(nil) + // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. func (iapd InterchainAccountPacketData) ValidateBasic() error { diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 92ed91ef58a..25fd1d74d42 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/authz" "github.com/cosmos/gogoproto/jsonpb" "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -29,6 +30,11 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &TransferAuthorization{}, ) + registry.RegisterImplementations( + (*exported.CallbackPacketDataI)(nil), + &FungibleTokenPacketData{} + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 0ba9d4e2835..0b1fef5775c 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ibcerrors "github.com/cosmos/ibc-go/v7/internal/errors" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) var ( @@ -24,6 +25,8 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) +var _ exported.CallbackPacketDataI = (*FungibleTokenPacketData)(nil) + // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( denom string, amount string, diff --git a/modules/core/exported/callbacks.go b/modules/core/exported/callbacks.go index a177d9f0bd1..755963f60c7 100644 --- a/modules/core/exported/callbacks.go +++ b/modules/core/exported/callbacks.go @@ -1,6 +1,6 @@ package exported -type CallbackPacketData interface { +type CallbackPacketDataI interface { // may return the empty string GetSrcCallbackAddress() string diff --git a/modules/core/exported/codec.go b/modules/core/exported/codec.go new file mode 100644 index 00000000000..aac25f4f317 --- /dev/null +++ b/modules/core/exported/codec.go @@ -0,0 +1,12 @@ +package exported + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" +) + +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterInterface( + "ibc.core.exported.v1.CallbackPacketDataI", + (*CallbackPacketDataI)(nil), + ) +} diff --git a/modules/core/types/codec.go b/modules/core/types/codec.go index e2c67424026..a44a5b5275b 100644 --- a/modules/core/types/codec.go +++ b/modules/core/types/codec.go @@ -7,6 +7,7 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ) @@ -18,4 +19,5 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { channeltypes.RegisterInterfaces(registry) commitmenttypes.RegisterInterfaces(registry) localhost.RegisterInterfaces(registry) + exported.RegisterInterfaces(registry) } From 3500d06decb234976cb36812b42f80c68d444e0d Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Mon, 13 Mar 2023 19:32:26 +0100 Subject: [PATCH 03/10] documentation --- .../27-interchain-accounts/types/packet.go | 26 +++++++++++++ modules/apps/transfer/types/packet.go | 37 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 25d032a7be5..0fe013ea15c 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -51,6 +51,32 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } +/** + +ADR-8 CallbackPacketData implementation + +InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +to retrieve the desired callback addresses for the ICA packet on the source and destination chains. + +The Memo is used to set the desired callback addresses. + +The Memo format is defined like so: + +```json +{ + // ... other memo fields we don't care about + "callbacks": { + "src_callback_address": {contractAddrOnSrcChain}, + "dest_callback_address": {contractAddrOnDestChain}, + "src_callback_msg": {jsonObjectForSrcChainCallback}, + "dest_callback_msg": {jsonObjectForDestChainCallback}, + } + +} +``` + +**/ + // ADR-8 middleware should callback on the sender address on the source chain // if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() (addr string) { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 0b1fef5775c..76466626190 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -67,8 +67,42 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } +/** + +ADR-8 CallbackPacketData implementation + +FungibleTokenPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +to retrieve the desired callback addresses for the ICS20 packet on the source and destination chains. + +The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet +to a contract with ADR-8 enabled without automatically triggering the callback logic which may lead to unexpected +behaviour. + +The Memo format is defined like so: + +```json +{ + // ... other memo fields we don't care about + "callbacks": { + "src_callback_address": {contractAddrOnSrcChain}, + "dest_callback_address": {contractAddrOnDestChain}, + "src_callback_msg": {jsonObjectForSrcChainCallback}, + "dest_callback_msg": {jsonObjectForDestChainCallback}, + } + +} +``` + +For transfer, we will enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. +However, we may remove this restriction at a later date if it proves useful. + +**/ + // ADR-8 middleware should callback on the sender address on the source chain // if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +// The desired callback address must be confirmed in the memo under the "callbacks" key. +// This ensures that the callback is explicitly desired by the user and not just called +// automatically. func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() (addr string) { if len(ftpd.Memo) == 0 { return @@ -94,6 +128,9 @@ func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() (addr string) { // ADR-8 middleware should callback on the receiver address on the destination chain // if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +// The desired callback address must be confirmed in the memo under the "callbacks" key. +// This ensures that the callback is explicitly desired by the user and not just called +// automatically. func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() (addr string) { if len(ftpd.Memo) == 0 { return From 89f608cf3f0e096ec4178a21f407dadaa047b0c6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sat, 18 Mar 2023 23:06:16 +0100 Subject: [PATCH 04/10] add comma before new line --- modules/apps/transfer/types/codec.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 25fd1d74d42..9ce27b43b8f 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -32,7 +32,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*exported.CallbackPacketDataI)(nil), - &FungibleTokenPacketData{} + &FungibleTokenPacketData{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) From b77cfe60f88979c677602f4c6f992771fbfd0626 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 22 Mar 2023 12:15:31 +0100 Subject: [PATCH 05/10] fix return arg and dest for ica --- .../27-interchain-accounts/types/packet.go | 41 ++++++------------- .../types/packet_test.go | 40 ++++++++++++++++++ modules/apps/transfer/types/packet.go | 20 ++++----- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 0fe013ea15c..0828820bb05 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -51,7 +51,7 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&iapd)) } -/** +/* ADR-8 CallbackPacketData implementation @@ -68,62 +68,47 @@ The Memo format is defined like so: "callbacks": { "src_callback_address": {contractAddrOnSrcChain}, "dest_callback_address": {contractAddrOnDestChain}, - "src_callback_msg": {jsonObjectForSrcChainCallback}, - "dest_callback_msg": {jsonObjectForDestChainCallback}, + "src_callback_msg": {jsonObjectForSrcChainCallback}, // optional field + "dest_callback_msg": {jsonObjectForDestChainCallback}, // optional field } } ``` -**/ +*/ +// GetSrcCallbackAddress returns the callback address on the source chain. // ADR-8 middleware should callback on the sender address on the source chain // if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() (addr string) { +func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { if len(iapd.Memo) == 0 { - return + return "" } jsonObject := make(map[string]interface{}) // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) if err != nil { - return + return "" } callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) if !ok { - return + return "" } callbackAddr := callbackData["src_callback_address"].(string) return callbackAddr } +// GetDestCallbackAddress returns the callback address on the destination chain. // ADR-8 middleware should callback on the receiver address on the destination chain // if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -func (iapd InterchainAccountPacketData) GetDestCallbackAddress() (addr string) { - if len(iapd.Memo) == 0 { - return - } - - jsonObject := make(map[string]interface{}) - // the jsonObject must be a valid JSON object - err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) - if err != nil { - return - } - - callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) - if !ok { - return - } - - callbackAddr := callbackData["dest_callback_address"].(string) - return callbackAddr +func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { + return "" } -// no-op on this method to use relayer passed in gas +// UserDefinedGasLimit no-ops on this method to use relayer passed in gas func (fptd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 329e5a837f4..38e5e2f9a4c 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -82,3 +82,43 @@ func (suite *TypesTestSuite) TestValidateBasic() { }) } } + +func (suite *TypesTestSuite) TestGetCallbackAddresses() { + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + expSrcCallbackAddr string + expDestCallbackAddr string + }{ + { + "memo is empty", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "", + }, + "", + "", + }, + { + "memo is not json string", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "memo", + }, + "", + "", + }, + { + "memo is does not have callbacks in json struct", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: json.MustMarshalJSON, + }, + "", + "", + }, + } +} diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 76466626190..f0ad9b0d419 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,27 +103,27 @@ However, we may remove this restriction at a later date if it proves useful. // The desired callback address must be confirmed in the memo under the "callbacks" key. // This ensures that the callback is explicitly desired by the user and not just called // automatically. -func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() (addr string) { +func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() string { if len(ftpd.Memo) == 0 { - return + return "" } jsonObject := make(map[string]interface{}) // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { - return + return "" } callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) if !ok { - return + return "" } if callbackData["src_callback_address"] == ftpd.Sender { return ftpd.Sender } - return + return "" } // ADR-8 middleware should callback on the receiver address on the destination chain @@ -131,27 +131,27 @@ func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() (addr string) { // The desired callback address must be confirmed in the memo under the "callbacks" key. // This ensures that the callback is explicitly desired by the user and not just called // automatically. -func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() (addr string) { +func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { if len(ftpd.Memo) == 0 { - return + return "" } jsonObject := make(map[string]interface{}) // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { - return + return "" } callbackData, ok := jsonObject["callbacks"].(map[string]interface{}) if !ok { - return + return "" } if callbackData["dest_callback_address"] == ftpd.Receiver { return ftpd.Receiver } - return + return "" } // no-op on this method to use relayer passed in gas From 1db462613689227d4838ee356c1a058f2e424210 Mon Sep 17 00:00:00 2001 From: Aditya Sripal Date: Wed, 22 Mar 2023 13:22:07 +0100 Subject: [PATCH 06/10] add ica tests --- .../27-interchain-accounts/types/packet.go | 5 ++- .../types/packet_test.go | 42 +++++++++++++++---- modules/apps/transfer/types/codec.go | 2 +- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 0828820bb05..57b4728135c 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -97,7 +97,10 @@ func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { return "" } - callbackAddr := callbackData["src_callback_address"].(string) + callbackAddr, ok := callbackData["src_callback_address"].(string) + if !ok { + return "" + } return callbackAddr } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 38e5e2f9a4c..77ea0df927c 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -85,10 +85,9 @@ func (suite *TypesTestSuite) TestValidateBasic() { func (suite *TypesTestSuite) TestGetCallbackAddresses() { testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expSrcCallbackAddr string - expDestCallbackAddr string + name string + packetData types.InterchainAccountPacketData + expSrcCallbackAddr string }{ { "memo is empty", @@ -98,7 +97,6 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Memo: "", }, "", - "", }, { "memo is not json string", @@ -108,17 +106,47 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Memo: "memo", }, "", - "", }, { "memo is does not have callbacks in json struct", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: json.MustMarshalJSON, + Memo: "{\"Key\": 10}", + }, + "", + }, + { + "memo has callbacks in json struct but does not have src_callback_address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "{\"callbacks\": {\"Key\": 10}}", }, "", + }, + { + "memo has callbacks in json struct but does not have string value for src_callback_address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "{\"callbacks\": {\"src_callback_address\": 10}}", + }, "", }, + { + "memo has callbacks in json struct but does not have string value for src_callback_address key", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: "{\"callbacks\": {\"src_callback_address\": \"testAddress\"}}", + }, + "testAddress", + }, + } + + for _, tc := range testCases { + srcCbAddr := tc.packetData.GetSrcCallbackAddress() + suite.Require().Equal(tc.expSrcCallbackAddr, srcCbAddr, "%s testcase does not have expected src_callback_address", tc.name) } } diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 25fd1d74d42..9ce27b43b8f 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -32,7 +32,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*exported.CallbackPacketDataI)(nil), - &FungibleTokenPacketData{} + &FungibleTokenPacketData{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) From f8298da855bdc5c882c2e03c9b42274156368920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:42:11 +0200 Subject: [PATCH 07/10] adr 8 callback packet data impl followups (#3325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove query client (#3227) * remove query client * merge main * go mod tidy * Rename ``IsBound`` to ``HasCapability`` (#3253) ## Description closes: #828 ### Commit Message / Changelog Entry ```bash imp(api!): rename `IsBound` to `HasCapability` for IBC application modules ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * chore: add support for tendermint debug log level (#3279) * build(deps): bump cosmossdk.io/math from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0 (#3285) Bumps [cosmossdk.io/math](https://github.com/cosmos/cosmos-sdk) from 1.0.0-beta.6.0.20230216172121-959ce49135e4 to 1.0.0-rc.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cosmossdk.io/math&package-manager=go_modules&previous-version=1.0.0-beta.6.0.20230216172121-959ce49135e4&new-version=1.0.0-rc.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
* Write docker inspect output to diagnostics (#3291) * chore: fix dead links (#3293) ## Description closes: #XXXX ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [x] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * build(deps): bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#3292) * deps: bump SDK v0.47 (#3295) Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove unnecessary import from doc * chore: remove support for v3 (#3294) * build(deps): bump actions/setup-go from 3 to 4 (#3307) * imp: remove unnecessary defer func statements (#3304) * Remove gogoproto yaml tags from proto files (#3290) ## Description Refer from original issue, I removed all `yaml` tags in proto files. closes: #3145 ### Commit Message / Changelog Entry ```bash type: commit message ``` see the [guidelines](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) for commit messages. (view raw markdown for examples) --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#pull-request-targeting)). - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules/10-structure.md) and [Go style guide](../docs/dev/go-style-guide.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/main/testing/README.md#ibc-testing-package). - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`). - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Provide a [commit message](https://github.com/cosmos/ibc-go/blob/main/docs/dev/pull-requests.md#commit-messages) to be used for the changelog entry in the PR description for review. - [ ] Re-reviewed `Files changed` in the Github PR explorer. - [ ] Review `Codecov Report` in the comment section below once CI passes. * add reasoning for migration to enable localhost * Support configuration file for e2e tests (#3260) * E2E fzf Test Selection Autocompletion (#3313) * post v7 release chores (#3310) * chore: fix linter warnings (#3311) * ADR 008: IBC Actor Callbacks (#1976) * context and decision * complete adr * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * change from caller to generalized actor * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * create folder and scaffolded middleware * add error handling and generify packetdata interface * complete renaming * add user defined gas limit and clarify pseudocode * Clarify CallbackPacketData interface imp: Add ADR 008: IBC Actor Callbacks --------- Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * lint: fix spelling * chore: apply self review concerns * chore: rename CallbackPacketDataI to CallbackPacketData * chore: finish applying remaining review suggestions * test: add remaining unit tests for transfer and ica * test: add unmarshaling test * imp: address ADR 8 review suggestions (#3319) --------- Co-authored-by: Damian Nolan * Bump interchain test (#3314) * fix: remove codec registration * fix: build + linting * Only run e2e on R4R (#3330) * fix fork workflows (#3328) * Revert "Merge branch 'main' of github.com:cosmos/ibc-go into colin/callback-packet-data-impl" This reverts commit 1c6164bd627e1ace7704efa1b0bae0d6f68f3587, reversing changes made to 6f25b8eecae5d4e6c4fca83cc17c37d2e38373d9. * chore: add optional interface godoc * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore: use backticks instead of escape characters in testing --------- Co-authored-by: Lặc <67097720+expertdicer@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Cian Hatton Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: GNaD13 <89174180+GNaD13@users.noreply.github.com> Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com> Co-authored-by: Aditya --- .../27-interchain-accounts/types/codec.go | 6 - .../27-interchain-accounts/types/packet.go | 37 +-- .../types/packet_test.go | 90 ++++++-- modules/apps/transfer/types/codec.go | 13 +- modules/apps/transfer/types/packet.go | 58 +++-- modules/apps/transfer/types/packet_test.go | 211 ++++++++++++++++++ modules/core/exported/callbacks.go | 19 -- modules/core/exported/channel.go | 20 -- modules/core/exported/codec.go | 12 - modules/core/exported/packet.go | 46 ++++ modules/core/types/codec.go | 2 - 11 files changed, 390 insertions(+), 124 deletions(-) delete mode 100644 modules/core/exported/callbacks.go delete mode 100644 modules/core/exported/codec.go create mode 100644 modules/core/exported/packet.go diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index 87436519415..b0ba7b8902b 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/ibc-go/v7/modules/core/exported" ) // ModuleCdc references the global interchain accounts module codec. Note, the codec @@ -22,11 +21,6 @@ var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*authtypes.AccountI)(nil), &InterchainAccount{}) registry.RegisterImplementations((*authtypes.GenesisAccount)(nil), &InterchainAccount{}) - - registry.RegisterImplementations( - (*exported.CallbackPacketDataI)(nil), - &InterchainAccountPacketData{}, - ) } // SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 57b4728135c..8e0b5aa9af0 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -26,7 +26,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketDataI = (*InterchainAccountPacketData)(nil) +var _ exported.CallbackPacketData = (*InterchainAccountPacketData)(nil) // ValidateBasic performs basic validation of the interchain account packet data. // The memo may be empty. @@ -55,7 +55,7 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { ADR-8 CallbackPacketData implementation -InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targeting specific VMs to retrieve the desired callback addresses for the ICA packet on the source and destination chains. The Memo is used to set the desired callback addresses. @@ -66,27 +66,32 @@ The Memo format is defined like so: { // ... other memo fields we don't care about "callbacks": { - "src_callback_address": {contractAddrOnSrcChain}, + "src_callback_address": {contractAddrOnSourceChain}, "dest_callback_address": {contractAddrOnDestChain}, - "src_callback_msg": {jsonObjectForSrcChainCallback}, // optional field - "dest_callback_msg": {jsonObjectForDestChainCallback}, // optional field - } + // optional fields + "src_callback_msg": {jsonObjectForSourceChainCallback}, + "dest_callback_msg": {jsonObjectForDestChainCallback}, + } } ``` */ -// GetSrcCallbackAddress returns the callback address on the source chain. -// ADR-8 middleware should callback on the sender address on the source chain -// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { +// GetSourceCallbackAddress returns the source callback address provided in the packet data memo. +// If no callback address is specified, an empty string is returned. +// +// The memo is expected to specify the callback address in the following format: +// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { if len(iapd.Memo) == 0 { return "" } jsonObject := make(map[string]interface{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(iapd.Memo), &jsonObject) if err != nil { return "" @@ -101,17 +106,19 @@ func (iapd InterchainAccountPacketData) GetSrcCallbackAddress() string { if !ok { return "" } + return callbackAddr } -// GetDestCallbackAddress returns the callback address on the destination chain. -// ADR-8 middleware should callback on the receiver address on the destination chain -// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) +// GetDestCallbackAddress returns an empty string. Destination callback addresses +// are not supported for ICS 27 since this feature is natively supported by +// interchain accounts host submodule transaction execution. func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" } -// UserDefinedGasLimit no-ops on this method to use relayer passed in gas +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. func (fptd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 77ea0df927c..5c2f000fd8e 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ) @@ -83,11 +85,13 @@ func (suite *TypesTestSuite) TestValidateBasic() { } } -func (suite *TypesTestSuite) TestGetCallbackAddresses() { +func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { + const expSrcCbAddr = "srcCbAddr" + testCases := []struct { - name string - packetData types.InterchainAccountPacketData - expSrcCallbackAddr string + name string + packetData types.InterchainAccountPacketData + expPass bool }{ { "memo is empty", @@ -96,7 +100,7 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Data: []byte("data"), Memo: "", }, - "", + false, }, { "memo is not json string", @@ -105,48 +109,98 @@ func (suite *TypesTestSuite) TestGetCallbackAddresses() { Data: []byte("data"), Memo: "memo", }, - "", + false, }, { - "memo is does not have callbacks in json struct", + "memo does not have callbacks in json struct", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "{\"Key\": 10}", + Memo: `{"Key": 10}`, }, - "", + false, }, { "memo has callbacks in json struct but does not have src_callback_address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "{\"callbacks\": {\"Key\": 10}}", + Memo: `{"callbacks": {"Key": 10}}`, }, - "", + false, }, { "memo has callbacks in json struct but does not have string value for src_callback_address key", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "{\"callbacks\": {\"src_callback_address\": 10}}", + Memo: `{"callbacks": {"src_callback_address": 10}}`, }, - "", + false, }, { - "memo has callbacks in json struct but does not have string value for src_callback_address key", + "memo has callbacks in json struct and properly formatted src_callback_address", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, expSrcCbAddr), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + srcCbAddr := tc.packetData.GetSourceCallbackAddress() + + if tc.expPass { + suite.Require().Equal(expSrcCbAddr, srcCbAddr) + } else { + suite.Require().Equal("", srcCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestGetDestCallbackAddress() { + testCases := []struct { + name string + packetData types.InterchainAccountPacketData + }{ + { + "memo is empty", types.InterchainAccountPacketData{ Type: types.EXECUTE_TX, Data: []byte("data"), - Memo: "{\"callbacks\": {\"src_callback_address\": \"testAddress\"}}", + Memo: "", + }, + }, + { + "memo has dest callback address specified in json struct", + types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, }, - "testAddress", }, } for _, tc := range testCases { - srcCbAddr := tc.packetData.GetSrcCallbackAddress() - suite.Require().Equal(tc.expSrcCallbackAddr, srcCbAddr, "%s testcase does not have expected src_callback_address", tc.name) + tc := tc + suite.Run(tc.name, func() { + destCbAddr := tc.packetData.GetDestCallbackAddress() + suite.Require().Equal("", destCbAddr) + }) + } +} + +func (suite *TypesTestSuite) TestUserDefinedGasLimit() { + packetData := types.InterchainAccountPacketData{ + Type: types.EXECUTE_TX, + Data: []byte("data"), + Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, } + + suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") } diff --git a/modules/apps/transfer/types/codec.go b/modules/apps/transfer/types/codec.go index 9ce27b43b8f..9692acdbae6 100644 --- a/modules/apps/transfer/types/codec.go +++ b/modules/apps/transfer/types/codec.go @@ -3,15 +3,13 @@ package types import ( "bytes" - "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/gogoproto/jsonpb" - "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/cosmos/gogoproto/jsonpb" + "github.com/cosmos/gogoproto/proto" ) // RegisterLegacyAminoCodec registers the necessary x/ibc transfer interfaces and concrete types @@ -30,11 +28,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &TransferAuthorization{}, ) - registry.RegisterImplementations( - (*exported.CallbackPacketDataI)(nil), - &FungibleTokenPacketData{}, - ) - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index f0ad9b0d419..67790ed622b 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -25,7 +25,7 @@ var ( DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds()) ) -var _ exported.CallbackPacketDataI = (*FungibleTokenPacketData)(nil) +var _ exported.CallbackPacketData = (*FungibleTokenPacketData)(nil) // NewFungibleTokenPacketData contructs a new FungibleTokenPacketData instance func NewFungibleTokenPacketData( @@ -67,11 +67,11 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { return sdk.MustSortJSON(mustProtoMarshalJSON(&ftpd)) } -/** +/* ADR-8 CallbackPacketData implementation -FungibleTokenPacketData implements CallbackPacketDataI interface. This will allow middlewares targetting specific VMs +FungibleTokenPacketData implements CallbackPacketDataI interface. This will allow middlewares targeting specific VMs to retrieve the desired callback addresses for the ICS20 packet on the source and destination chains. The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet @@ -84,32 +84,38 @@ The Memo format is defined like so: { // ... other memo fields we don't care about "callbacks": { - "src_callback_address": {contractAddrOnSrcChain}, + "src_callback_address": {contractAddrOnSourceChain}, "dest_callback_address": {contractAddrOnDestChain}, - "src_callback_msg": {jsonObjectForSrcChainCallback}, + + // optional fields + "src_callback_msg": {jsonObjectForSourceChainCallback}, "dest_callback_msg": {jsonObjectForDestChainCallback}, } - } ``` For transfer, we will enforce that the src_callback_address is the same as sender and dest_callback_address is the same as receiver. However, we may remove this restriction at a later date if it proves useful. -**/ - -// ADR-8 middleware should callback on the sender address on the source chain -// if the sender address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -// The desired callback address must be confirmed in the memo under the "callbacks" key. -// This ensures that the callback is explicitly desired by the user and not just called -// automatically. -func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() string { +*/ + +// GetSourceCallbackAddress returns the sender address if it is also specified in +// the packet data memo. The desired callback address must be confirmed in the +// memo under the "callbacks" key. This ensures that the callback is explicitly +// desired by the user and not called automatically. If no callback address is +// specified, an empty string is returned. +// +// The memo is expected to contain the source callback address in the following format: +// { "callbacks": { "src_callback_address": {contractAddrOnSourceChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). +func (ftpd FungibleTokenPacketData) GetSourceCallbackAddress() string { if len(ftpd.Memo) == 0 { return "" } jsonObject := make(map[string]interface{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { return "" @@ -123,21 +129,27 @@ func (ftpd FungibleTokenPacketData) GetSrcCallbackAddress() string { if callbackData["src_callback_address"] == ftpd.Sender { return ftpd.Sender } + return "" } -// ADR-8 middleware should callback on the receiver address on the destination chain -// if the receiver address is an IBC Actor (i.e. smart contract that accepts IBC callbacks) -// The desired callback address must be confirmed in the memo under the "callbacks" key. -// This ensures that the callback is explicitly desired by the user and not just called -// automatically. +// GetDestCallbackAddress returns the receiving address if it is also specified in +// the packet data memo. The desired callback address must be confirmed in the +// memo under the "callbacks" key. This ensures that the callback is explicitly +// desired by the user and not called automatically. If no callback address is +// specified, an empty string is returned. +// +// The memo is expected to contain the destination callback address in the following format: +// { "callbacks": { "dest_callback_address": {contractAddrOnDestChain}} +// +// ADR-8 middleware should callback on the returned address if it is a PacketActor +// (i.e. smart contract that accepts IBC callbacks). func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { if len(ftpd.Memo) == 0 { return "" } jsonObject := make(map[string]interface{}) - // the jsonObject must be a valid JSON object err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) if err != nil { return "" @@ -151,10 +163,12 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { if callbackData["dest_callback_address"] == ftpd.Receiver { return ftpd.Receiver } + return "" } -// no-op on this method to use relayer passed in gas +// UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing +// transaction will be used. func (fptd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 067169a4ba2..62b12da1540 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -43,3 +44,213 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { } } } + +func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expPass bool + }{ + { + "memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"Key": 10}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have src_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"Key": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have string value for src_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"src_callback_address": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct and properly formatted src_callback_address which does not match packet sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"src_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid src_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, addr1), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + srcCbAddr := tc.packetData.GetSourceCallbackAddress() + + if tc.expPass { + suite.Require().Equal(addr1, srcCbAddr) + } else { + suite.Require().Equal("", srcCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestGetDestCallbackAddress() { + testCases := []struct { + name string + packetData types.FungibleTokenPacketData + expPass bool + }{ + { + "memo is empty", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "", + }, + false, + }, + { + "memo is not json string", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: "memo", + }, + false, + }, + { + "memo does not have callbacks in json struct", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"Key": 10}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have dest_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"Key": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct but does not have string value for dest_callback_address key", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"dest_callback_address": 10}}`, + }, + false, + }, + { + "memo has callbacks in json struct and properly formatted dest_callback_address which does not match packet sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, + }, + false, + }, + { + "valid dest_callback_address specified in memo that matches sender", + types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, addr2), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + destCbAddr := tc.packetData.GetDestCallbackAddress() + + if tc.expPass { + suite.Require().Equal(addr2, destCbAddr) + } else { + suite.Require().Equal("", destCbAddr) + } + }) + } +} + +func (suite *TypesTestSuite) TestUserDefinedGasLimit() { + packetData := types.FungibleTokenPacketData{ + Denom: denom, + Amount: amount, + Sender: addr1, + Receiver: addr2, + Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, + } + + suite.Require().Equal(uint64(0), packetData.UserDefinedGasLimit(), "user defined gas limit does not return 0") +} diff --git a/modules/core/exported/callbacks.go b/modules/core/exported/callbacks.go deleted file mode 100644 index 755963f60c7..00000000000 --- a/modules/core/exported/callbacks.go +++ /dev/null @@ -1,19 +0,0 @@ -package exported - -type CallbackPacketDataI interface { - // may return the empty string - GetSrcCallbackAddress() string - - // may return the empty string - GetDestCallbackAddress() string - - // UserDefinedGasLimit allows the sender of the packet to define inside the packet data - // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed - // in as the gas limit so that the callback is guaranteed to complete within a specific limit. - // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. - // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still - // commit the transaction. This ensures the packet lifecycle can always complete. - // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) - // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` - UserDefinedGasLimit() uint64 -} diff --git a/modules/core/exported/channel.go b/modules/core/exported/channel.go index f6393393513..a6ec511880b 100644 --- a/modules/core/exported/channel.go +++ b/modules/core/exported/channel.go @@ -17,23 +17,3 @@ type CounterpartyChannelI interface { GetChannelID() string ValidateBasic() error } - -// PacketI defines the standard interface for IBC packets -type PacketI interface { - GetSequence() uint64 - GetTimeoutHeight() Height - GetTimeoutTimestamp() uint64 - GetSourcePort() string - GetSourceChannel() string - GetDestPort() string - GetDestChannel() string - GetData() []byte - ValidateBasic() error -} - -// Acknowledgement defines the interface used to return -// acknowledgements in the OnRecvPacket callback. -type Acknowledgement interface { - Success() bool - Acknowledgement() []byte -} diff --git a/modules/core/exported/codec.go b/modules/core/exported/codec.go deleted file mode 100644 index aac25f4f317..00000000000 --- a/modules/core/exported/codec.go +++ /dev/null @@ -1,12 +0,0 @@ -package exported - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" -) - -func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterInterface( - "ibc.core.exported.v1.CallbackPacketDataI", - (*CallbackPacketDataI)(nil), - ) -} diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go new file mode 100644 index 00000000000..109cc246d4f --- /dev/null +++ b/modules/core/exported/packet.go @@ -0,0 +1,46 @@ +package exported + +// PacketI defines the standard interface for IBC packets +type PacketI interface { + GetSequence() uint64 + GetTimeoutHeight() Height + GetTimeoutTimestamp() uint64 + GetSourcePort() string + GetSourceChannel() string + GetDestPort() string + GetDestChannel() string + GetData() []byte + ValidateBasic() error +} + +// Acknowledgement defines the interface used to return +// acknowledgements in the OnRecvPacket callback. +type Acknowledgement interface { + Success() bool + Acknowledgement() []byte +} + +// CallbackPacketData defines the interface used by ADR 8 implementations +// to obtain callback addresses associated with a specific packet data type. +// This is an optional interface which indicates support for ADR 8 implementations. +type CallbackPacketData interface { + // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. + // This may or may not be the sender of the packet. If no source callback address exists for the packet, + // an empty string may be returned. + GetSourceCallbackAddress() string + + // GetDestCallbackAddress should return the callback address of a packet data on the destination chain. + // This may or may not be the receiver of the packet. If no dest callback address exists for the packet, + // an empty string may be returned. + GetDestCallbackAddress() string + + // UserDefinedGasLimit allows the sender of the packet to define inside the packet data + // a gas limit for how much the ADR-8 callbacks can consume. If defined, this will be passed + // in as the gas limit so that the callback is guaranteed to complete within a specific limit. + // On recvPacket, a gas-overflow will just fail the transaction allowing it to timeout on the sender side. + // On ackPacket and timeoutPacket, a gas-overflow will reject state changes made during callback but still + // commit the transaction. This ensures the packet lifecycle can always complete. + // If the packet data returns 0, the remaining gas limit will be passed in (modulo any chain-defined limit) + // Otherwise, we will set the gas limit passed into the callback to the `min(ctx.GasLimit, UserDefinedGasLimit())` + UserDefinedGasLimit() uint64 +} diff --git a/modules/core/types/codec.go b/modules/core/types/codec.go index a44a5b5275b..e2c67424026 100644 --- a/modules/core/types/codec.go +++ b/modules/core/types/codec.go @@ -7,7 +7,6 @@ import ( connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v7/modules/core/exported" localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ) @@ -19,5 +18,4 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { channeltypes.RegisterInterfaces(registry) commitmenttypes.RegisterInterfaces(registry) localhost.RegisterInterfaces(registry) - exported.RegisterInterfaces(registry) } From ca33576fc8fd707a4f8bf01dc7f20b597b9cfad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 27 Mar 2023 17:57:40 +0200 Subject: [PATCH 08/10] fix: merge conflicts --- modules/apps/transfer/types/packet_test.go | 68 +++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index bb64b422eb6..05ee8ec74a2 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -56,8 +56,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: "", }, false, @@ -67,8 +67,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: "memo", }, false, @@ -78,8 +78,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"Key": 10}`, }, false, @@ -89,8 +89,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"Key": 10}}`, }, false, @@ -100,8 +100,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"src_callback_address": 10}}`, }, false, @@ -111,8 +111,8 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"src_callback_address": "testAddress"}}`, }, false, @@ -122,9 +122,9 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, - Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, addr1), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callbacks": {"src_callback_address": "%s"}}`, sender), }, true, }, @@ -136,7 +136,7 @@ func (suite *TypesTestSuite) TestGetSourceCallbackAddress() { srcCbAddr := tc.packetData.GetSourceCallbackAddress() if tc.expPass { - suite.Require().Equal(addr1, srcCbAddr) + suite.Require().Equal(sender, srcCbAddr) } else { suite.Require().Equal("", srcCbAddr) } @@ -155,8 +155,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: "", }, false, @@ -166,8 +166,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: "memo", }, false, @@ -177,8 +177,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"Key": 10}`, }, false, @@ -188,8 +188,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"Key": 10}}`, }, false, @@ -199,8 +199,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"dest_callback_address": 10}}`, }, false, @@ -210,8 +210,8 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"dest_callback_address": "testAddress"}}`, }, false, @@ -221,9 +221,9 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, - Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, addr2), + Sender: sender, + Receiver: receiver, + Memo: fmt.Sprintf(`{"callbacks": {"dest_callback_address": "%s"}}`, receiver), }, true, }, @@ -235,7 +235,7 @@ func (suite *TypesTestSuite) TestGetDestCallbackAddress() { destCbAddr := tc.packetData.GetDestCallbackAddress() if tc.expPass { - suite.Require().Equal(addr2, destCbAddr) + suite.Require().Equal(receiver, destCbAddr) } else { suite.Require().Equal("", destCbAddr) } @@ -247,8 +247,8 @@ func (suite *TypesTestSuite) TestUserDefinedGasLimit() { packetData := types.FungibleTokenPacketData{ Denom: denom, Amount: amount, - Sender: addr1, - Receiver: addr2, + Sender: sender, + Receiver: receiver, Memo: `{"callbacks": {"user_defined_gas_limit": 100}}`, } From 6bf400e4e92644d12ecbac758759a9dcea8db234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 27 Mar 2023 18:04:29 +0200 Subject: [PATCH 09/10] chore: nits from self review --- modules/apps/27-interchain-accounts/types/packet.go | 11 +++++------ modules/apps/transfer/types/packet.go | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/packet.go b/modules/apps/27-interchain-accounts/types/packet.go index 8e0b5aa9af0..71551671c3c 100644 --- a/modules/apps/27-interchain-accounts/types/packet.go +++ b/modules/apps/27-interchain-accounts/types/packet.go @@ -55,8 +55,9 @@ func (iapd InterchainAccountPacketData) GetBytes() []byte { ADR-8 CallbackPacketData implementation -InterchainAccountPacketData implements CallbackPacketDataI interface. This will allow middlewares targeting specific VMs -to retrieve the desired callback addresses for the ICA packet on the source and destination chains. +InterchainAccountPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs +to retrieve the desired callback address for the ICA packet on the source chain. Destination callback addresses are not +supported for ICS 27. The Memo is used to set the desired callback addresses. @@ -67,11 +68,9 @@ The Memo format is defined like so: // ... other memo fields we don't care about "callbacks": { "src_callback_address": {contractAddrOnSourceChain}, - "dest_callback_address": {contractAddrOnDestChain}, // optional fields "src_callback_msg": {jsonObjectForSourceChainCallback}, - "dest_callback_msg": {jsonObjectForDestChainCallback}, } } ``` @@ -111,7 +110,7 @@ func (iapd InterchainAccountPacketData) GetSourceCallbackAddress() string { } // GetDestCallbackAddress returns an empty string. Destination callback addresses -// are not supported for ICS 27 since this feature is natively supported by +// are not supported for ICS 27. This feature is natively supported by // interchain accounts host submodule transaction execution. func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { return "" @@ -119,7 +118,7 @@ func (iapd InterchainAccountPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing // transaction will be used. -func (fptd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { +func (iapd InterchainAccountPacketData) UserDefinedGasLimit() uint64 { return 0 } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 67790ed622b..20080e623f8 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -71,7 +71,7 @@ func (ftpd FungibleTokenPacketData) GetBytes() []byte { ADR-8 CallbackPacketData implementation -FungibleTokenPacketData implements CallbackPacketDataI interface. This will allow middlewares targeting specific VMs +FungibleTokenPacketData implements CallbackPacketData interface. This will allow middlewares targeting specific VMs to retrieve the desired callback addresses for the ICS20 packet on the source and destination chains. The Memo is used to ensure that the callback is desired by the user. This allows a user to send an ICS20 packet @@ -169,6 +169,6 @@ func (ftpd FungibleTokenPacketData) GetDestCallbackAddress() string { // UserDefinedGasLimit returns 0 (no-op). The gas limit of the executing // transaction will be used. -func (fptd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { +func (ftpd FungibleTokenPacketData) UserDefinedGasLimit() uint64 { return 0 } From 523f40b017821c13b750c507e7a361afe66328fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:11:24 +0200 Subject: [PATCH 10/10] chore: add link to ADR 008 in godoc --- modules/core/exported/packet.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index 109cc246d4f..39c9dc3fdb6 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -20,9 +20,11 @@ type Acknowledgement interface { Acknowledgement() []byte } -// CallbackPacketData defines the interface used by ADR 8 implementations +// CallbackPacketData defines the interface used by ADR 008 implementations // to obtain callback addresses associated with a specific packet data type. // This is an optional interface which indicates support for ADR 8 implementations. +// See https://github.com/cosmos/ibc-go/tree/main/docs/architecture/adr-008-app-caller-cbs +// for more information. type CallbackPacketData interface { // GetSourceCallbackAddress should return the callback address of a packet data on the source chain. // This may or may not be the sender of the packet. If no source callback address exists for the packet,