Skip to content

Commit 001b498

Browse files
nicolaslaramergify[bot]
authored andcommitted
Added optional packet metadata to the packet and message types (#2305)
* added optional packet metadata to the packet and message types * added docs * breaking the api (backports should add a utility function for this) * adding nil metadata on all the calls * added metadata to the cli * added events * breaking api for FungibleTokenPacketData * hex encoding metadata * added abstraction * fixed bad merge * added tests with metadata * added missing metadata to packet for recv * cleaning up metadata on every test * reset metadata * added metadata flag * lint * Update modules/apps/transfer/client/cli/tx.go Co-authored-by: Damian Nolan <damiannolan@gmail.com> * fixed bad call in tests Co-authored-by: Damian Nolan <damiannolan@gmail.com> (cherry picked from commit 82397d6) # Conflicts: # docs/apps/transfer/messages.md # docs/ibc/proto-docs.md # go.mod # go.sum # modules/apps/29-fee/transfer_test.go # modules/apps/transfer/ibc_module.go # modules/apps/transfer/keeper/mbt_relay_test.go # modules/apps/transfer/keeper/relay_test.go # modules/apps/transfer/spec/05_events.md # modules/apps/transfer/types/packet.pb.go # modules/apps/transfer/types/tx.pb.go # proto/ibc/applications/interchain_accounts/controller/v1/tx.proto
1 parent d4aeb26 commit 001b498

24 files changed

Lines changed: 504 additions & 38 deletions

File tree

docs/apps/transfer/messages.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!--
2+
order: 4
3+
-->
4+
5+
# Messages
6+
7+
## `MsgTransfer`
8+
9+
A fungible token cross chain transfer is achieved by using the `MsgTransfer`:
10+
11+
```go
12+
type MsgTransfer struct {
13+
SourcePort string
14+
SourceChannel string
15+
Token sdk.Coin
16+
Sender string
17+
Receiver string
18+
TimeoutHeight ibcexported.Height
19+
TimeoutTimestamp uint64
20+
Metadata []byte
21+
}
22+
```
23+
24+
This message is expected to fail if:
25+
26+
- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators).
27+
- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)).
28+
- `Token` is invalid (denom is invalid or amount is negative)
29+
- `Token.Amount` is not positive.
30+
- `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](../../../docs/architecture/adr-001-coin-source-tracing.md).
31+
- `Sender` is empty.
32+
- `Receiver` is empty.
33+
- `TimeoutHeight` and `TimeoutTimestamp` are both zero.
34+
35+
This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`.
36+
37+
The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain.

docs/ibc/proto-docs.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,13 +1097,24 @@ identifier fields.
10971097

10981098
| Field | Type | Label | Description |
10991099
| ----- | ---- | ----- | ----------- |
1100+
<<<<<<< HEAD
11001101
| `state` | [State](#ibc.core.channel.v1.State) | | current state of the channel end |
11011102
| `ordering` | [Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered |
11021103
| `counterparty` | [Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end |
11031104
| `connection_hops` | [string](#string) | repeated | list of connection identifiers, in order, along which packets sent on this channel will travel |
11041105
| `version` | [string](#string) | | opaque channel version, which is agreed upon during the handshake |
11051106
| `port_id` | [string](#string) | | port identifier |
11061107
| `channel_id` | [string](#string) | | channel identifier |
1108+
=======
1109+
| `source_port` | [string](#string) | | the port on which the packet will be sent |
1110+
| `source_channel` | [string](#string) | | the channel by which the packet will be sent |
1111+
| `token` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | the tokens to be transferred |
1112+
| `sender` | [string](#string) | | the sender address |
1113+
| `receiver` | [string](#string) | | the recipient address on the destination chain |
1114+
| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | Timeout height relative to the current block height. The timeout is disabled when set to 0. |
1115+
| `timeout_timestamp` | [uint64](#uint64) | | Timeout timestamp in absolute nanoseconds since unix epoch. The timeout is disabled when set to 0. |
1116+
| `metadata` | [bytes](#bytes) | | optional metadata |
1117+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
11071118
11081119

11091120

@@ -1118,6 +1129,7 @@ Packet defines a type that carries data across different chains through IBC
11181129

11191130
| Field | Type | Label | Description |
11201131
| ----- | ---- | ----- | ----------- |
1132+
<<<<<<< HEAD
11211133
| `sequence` | [uint64](#uint64) | | number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. |
11221134
| `source_port` | [string](#string) | | identifies the port on the sending chain. |
11231135
| `source_channel` | [string](#string) | | identifies the channel end on the sending chain. |
@@ -1126,6 +1138,12 @@ Packet defines a type that carries data across different chains through IBC
11261138
| `data` | [bytes](#bytes) | | actual opaque bytes transferred directly to the application module |
11271139
| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | block height after which the packet times out |
11281140
| `timeout_timestamp` | [uint64](#uint64) | | block timestamp (in nanoseconds) after which the packet times out |
1141+
=======
1142+
| `sequence` | [uint64](#uint64) | | sequence number of the transfer packet sent |
1143+
1144+
1145+
1146+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
11291147
11301148

11311149

@@ -1166,6 +1184,16 @@ Order defines if a channel is ORDERED or UNORDERED
11661184
| ORDER_UNORDERED | 1 | packets can be delivered in any order, which may differ from the order in which they were sent. |
11671185
| ORDER_ORDERED | 2 | packets are delivered exactly in the order which they were sent |
11681186

1187+
<<<<<<< HEAD
1188+
=======
1189+
| Field | Type | Label | Description |
1190+
| ----- | ---- | ----- | ----------- |
1191+
| `denom` | [string](#string) | | the token denomination to be transferred |
1192+
| `amount` | [string](#string) | | the token amount to be transferred |
1193+
| `sender` | [string](#string) | | the sender address |
1194+
| `receiver` | [string](#string) | | the recipient address on the destination chain |
1195+
| `metadata` | [bytes](#bytes) | | optional metadata |
1196+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
11691197
11701198

11711199
<a name="ibc.core.channel.v1.State"></a>

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ require (
3535
github.com/beorn7/perks v1.0.1 // indirect
3636
github.com/bgentry/speakeasy v0.1.0 // indirect
3737
github.com/btcsuite/btcd v0.22.1 // indirect
38+
<<<<<<< HEAD
39+
=======
40+
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
41+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
3842
github.com/cespare/xxhash v1.1.0 // indirect
3943
github.com/cespare/xxhash/v2 v2.1.2 // indirect
4044
github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
130130
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
131131
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
132132
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
133+
<<<<<<< HEAD
134+
=======
135+
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
136+
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
137+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
133138
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
134139
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
135140
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package fee_test
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
6+
"github.com/cosmos/ibc-go/v6/modules/apps/29-fee/types"
7+
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
8+
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
9+
ibctesting "github.com/cosmos/ibc-go/v6/testing"
10+
)
11+
12+
// Integration test to ensure ics29 works with ics20
13+
func (suite *FeeTestSuite) TestFeeTransfer() {
14+
path := ibctesting.NewPath(suite.chainA, suite.chainB)
15+
feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version}))
16+
path.EndpointA.ChannelConfig.Version = feeTransferVersion
17+
path.EndpointB.ChannelConfig.Version = feeTransferVersion
18+
path.EndpointA.ChannelConfig.PortID = transfertypes.PortID
19+
path.EndpointB.ChannelConfig.PortID = transfertypes.PortID
20+
21+
suite.coordinator.Setup(path)
22+
23+
// set up coin & ics20 packet
24+
coin := ibctesting.TestCoin
25+
fee := types.Fee{
26+
RecvFee: defaultRecvFee,
27+
AckFee: defaultAckFee,
28+
TimeoutFee: defaultTimeoutFee,
29+
}
30+
31+
msgs := []sdk.Msg{
32+
types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil),
33+
transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, nil),
34+
}
35+
res, err := suite.chainA.SendMsgs(msgs...)
36+
suite.Require().NoError(err) // message committed
37+
38+
// after incentivizing the packets
39+
originalChainASenderAccountBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom))
40+
41+
packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents())
42+
suite.Require().NoError(err)
43+
44+
// register counterparty address on chainB
45+
// relayerAddress is address of sender account on chainB, but we will use it on chainA
46+
// to differentiate from the chainA.SenderAccount for checking successful relay payouts
47+
relayerAddress := suite.chainB.SenderAccount.GetAddress()
48+
49+
msgRegister := types.NewMsgRegisterCounterpartyPayee(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String())
50+
_, err = suite.chainB.SendMsgs(msgRegister)
51+
suite.Require().NoError(err) // message committed
52+
53+
// relay packet
54+
err = path.RelayPacket(packet)
55+
suite.Require().NoError(err) // relay committed
56+
57+
// ensure relayers got paid
58+
// relayer for forward relay: chainB.SenderAccount
59+
// relayer for reverse relay: chainA.SenderAccount
60+
61+
// check forward relay balance
62+
suite.Require().Equal(
63+
fee.RecvFee,
64+
sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)),
65+
)
66+
67+
suite.Require().Equal(
68+
fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded
69+
sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)).Sub(originalChainASenderAccountBalance[0]))
70+
}

modules/apps/transfer/client/cli/tx.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
flagPacketTimeoutHeight = "packet-timeout-height"
2323
flagPacketTimeoutTimestamp = "packet-timeout-timestamp"
2424
flagAbsoluteTimeouts = "absolute-timeouts"
25+
flagMetadata = "metadata"
2526
)
2627

2728
// NewTransferTxCmd returns the command to create a NewMsgTransfer transaction
@@ -76,6 +77,11 @@ corresponding to the counterparty channel. Any timeout set to 0 is disabled.`),
7677
return err
7778
}
7879

80+
metadataStr, err := cmd.Flags().GetString(flagMetadata)
81+
if err != nil {
82+
return err
83+
}
84+
7985
// if the timeouts are not absolute, retrieve latest block height and block timestamp
8086
// for the consensus state connected to the destination port/channel
8187
if !absoluteTimeouts {
@@ -111,7 +117,7 @@ corresponding to the counterparty channel. Any timeout set to 0 is disabled.`),
111117
}
112118

113119
msg := types.NewMsgTransfer(
114-
srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp,
120+
srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp, []byte(metadataStr),
115121
)
116122
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
117123
},
@@ -120,6 +126,7 @@ corresponding to the counterparty channel. Any timeout set to 0 is disabled.`),
120126
cmd.Flags().String(flagPacketTimeoutHeight, types.DefaultRelativePacketTimeoutHeight, "Packet timeout block height. The timeout is disabled when set to 0-0.")
121127
cmd.Flags().Uint64(flagPacketTimeoutTimestamp, types.DefaultRelativePacketTimeoutTimestamp, "Packet timeout timestamp in nanoseconds from now. Default is 10 minutes. The timeout is disabled when set to 0.")
122128
cmd.Flags().Bool(flagAbsoluteTimeouts, false, "Timeout flags are used as absolute timeouts.")
129+
cmd.Flags().String(flagMetadata, "", "Metadata to be sent along with the packet. The CLI accepts only strings here but you can construct a packet with arbitrary bytes via code.")
123130
flags.AddTxFlagsToCmd(cmd)
124131

125132
return cmd

modules/apps/transfer/ibc_module.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package transfer
22

33
import (
4+
"encoding/hex"
45
"fmt"
56
"math"
67

@@ -186,6 +187,23 @@ func (im IBCModule) OnRecvPacket(
186187
}
187188
}
188189

190+
<<<<<<< HEAD
191+
=======
192+
eventAttributes := []sdk.Attribute{
193+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
194+
sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
195+
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
196+
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
197+
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
198+
sdk.NewAttribute(types.AttributeKeyMetadata, hex.EncodeToString(data.Metadata)),
199+
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())),
200+
}
201+
202+
if ackErr != nil {
203+
eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error()))
204+
}
205+
206+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
189207
ctx.EventManager().EmitEvent(
190208
sdk.NewEvent(
191209
types.EventTypePacket,
@@ -230,6 +248,7 @@ func (im IBCModule) OnAcknowledgementPacket(
230248
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
231249
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
232250
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
251+
sdk.NewAttribute(types.AttributeKeyMetadata, hex.EncodeToString(data.Metadata)),
233252
sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
234253
),
235254
)
@@ -276,6 +295,7 @@ func (im IBCModule) OnTimeoutPacket(
276295
sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
277296
sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom),
278297
sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount),
298+
sdk.NewAttribute(types.AttributeKeyMetadata, hex.EncodeToString(data.Metadata)),
279299
),
280300
)
281301

modules/apps/transfer/keeper/mbt_relay_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack
145145
DenomFromTla(packet.Data.Denom),
146146
packet.Data.Amount,
147147
AddressFromString(packet.Data.Sender),
148-
AddressFromString(packet.Data.Receiver)),
148+
AddressFromString(packet.Data.Receiver),
149+
nil),
149150
}
150151
}
151152

@@ -344,8 +345,14 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() {
344345
sdk.NewCoin(denom, amount),
345346
sender,
346347
tc.packet.Data.Receiver,
348+
<<<<<<< HEAD
347349
clienttypes.NewHeight(0, 110),
348350
0)
351+
=======
352+
clienttypes.NewHeight(1, 110),
353+
0,
354+
nil)
355+
>>>>>>> 82397d6 (Added optional packet metadata to the packet and message types (#2305))
349356
}
350357
case "OnRecvPacket":
351358
err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data)

modules/apps/transfer/keeper/msg_server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.
2121

2222
sequence, err := k.sendTransfer(
2323
ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp,
24-
)
24+
msg.Metadata)
2525
if err != nil {
2626
return nil, err
2727
}

modules/apps/transfer/keeper/msg_server_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() {
5454
path.EndpointA.ChannelID,
5555
coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(),
5656
suite.chainB.GetTimeoutHeight(), 0, // only use timeout height
57+
[]byte("custom metadata"),
5758
)
5859

5960
tc.malleate()

0 commit comments

Comments
 (0)