diff --git a/docs/docs/01-ibc/01-overview.md b/docs/docs/01-ibc/01-overview.md index 8306fcaef8a..3342ec6a581 100644 --- a/docs/docs/01-ibc/01-overview.md +++ b/docs/docs/01-ibc/01-overview.md @@ -5,7 +5,6 @@ sidebar_position: 1 slug: /ibc/overview --- - # Overview :::note Synopsis diff --git a/docs/docs/02-apps/01-transfer/01-overview.md b/docs/docs/02-apps/01-transfer/01-overview.md index 1e308eb3fdf..bcadb09af5f 100644 --- a/docs/docs/02-apps/01-transfer/01-overview.md +++ b/docs/docs/02-apps/01-transfer/01-overview.md @@ -112,6 +112,49 @@ chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide m The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. ::: +## Forwarding + +:::info +Token forwarding and unwinding is supported only on ICS20 v2 transfer channels. +::: + +Forwarding allows tokens to be routed to a final destination through multiple (up to 8) intermediary +chains. With forwarding, it's also possible to unwind IBC vouchers to their native chain, and forward +them afterwards to another destination, all with just a single transfer transaction on the sending chain. + +### Forward tokens + +Native tokens or IBC vouchers on any chain can be forwarded through intermediary chains to reach their +final destination. For example, given the topology below, with 3 chains and a transfer channel between +chains A and B and between chains B and C: + +![Light Mode Forwarding](./images/forwarding-3-chains-light.png#gh-light-mode-only)![Dark Mode Forwarding](./images/forwarding-3-chains-dark.png#gh-dark-mode-only) + +Native tokens on chain `A` can be sent to chain `C` through chain `B`. The routing is specified by the +source port ID and channel ID of choice on every intermediary chain. In this example, there is only one +forwarding hop on chain `B` and the port ID, channel ID pair is `transfer`, `channelBToC`. Forwarding of +a multi-denom collections of tokens is also allowed (i.e. forwarding of tokens of different denominations). + +### Unwind tokens + +Taking again as an example the topology from the previous section, we assume that native tokens on chain `A` +have been transfered to chain `C`. The IBC vouchers on chain `C` have the denomination trace +`transfer/channelCtoB/transfer/channelBtoA`, and with forwarding it is possible to submit a transfer message +on chain `C` and automatically unwind the vouchers through chain `B` to chain `A`, so that the tokens recovered +on the origin chain regain their native denomination. In order to execute automatic unwinding, the transfer +module does not require extra user input: the unwind route is encoded in the denomination trace with the +pairs of destination port ID, channel ID that are added on every chain where the tokens are received. + +Please note that unwinding of vouchers is only allowed when vouchers of a single IBC denomination are +transferred (i.e. it is not possible to unwind vouchers of two different IBC denominations, since they +come from different source chains). + +### Unwind tokens and then forward + +Unwinding and forwarding can be used in combination, so that vouchers are first unwound to their origin chain +and then forwarded to a final destination. The same restriction as in the unwinding case applies: only vouchers +of a single IBC denomination can be used. + ## Locked funds In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. diff --git a/docs/docs/02-apps/01-transfer/04-messages.md b/docs/docs/02-apps/01-transfer/04-messages.md index 43cdf32a3e2..e6523f0fddc 100644 --- a/docs/docs/02-apps/01-transfer/04-messages.md +++ b/docs/docs/02-apps/01-transfer/04-messages.md @@ -23,10 +23,25 @@ type MsgTransfer struct { TimeoutTimestamp uint64 Memo string Tokens []sdk.Coin + Forwarding *Forwarding +} + +type Forwarding struct { + Unwind bool + Hops []Hop +} + +type Hop struct { + PortId string + ChannelId string } ``` -This message is expected to fail if: +:::info +Multi-denom token transfers and token forwarding are features supported only on ICS20 v2 transfer channels. +::: + +If `Forwarding` is `nil`, this message is expected to fail if: - `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). - `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)). @@ -39,6 +54,11 @@ This message is expected to fail if: - `Memo` contains more than 32768 bytes. - `TimeoutHeight` and `TimeoutTimestamp` are both zero. +If `Forwarding` is not `nil`, then to use forwarding you must either set `Unwind` to true or provide a non-empty list of `Hops`. Setting both `Unwind` to true and providing a non-empty list of `Hops` is allowed, but the total number of hops that is formed as a combination of the hops needed to unwind the tokens and the hops to forward them afterwards to the final destination must not exceed 8. When using forwarding, timeout must be specified using only `TimeoutTimestamp` (i.e. `TimeoutHeight` must be zero). Please note that the timeout timestamp must take into account the time that it may take tokens to be forwarded through the intermediary chains. Additionally, please note that the `MsgTransfer` will fail if: + +- `Hops` is not empty, and the number of elements of `Hops` is greater than 8, or either the `PortId` or `ChannelId` of any of the `Hops` is not a valid identifier. +- `Unwind` is true, and either the number of elements in `Tokens` is greater than 1, or `SourcePort` and `SourceChannel` are not empty strings (they must be empty because they are set by the transfer module, since it has access to the denomination trace information and is thus able to know the source port ID, channel ID to use in order to unwind the tokens). If `Unwind` is true, the transfer module expects the tokens in `MsgTransfer` to not be native to the sending chain (i.e. they must be IBC vouchers). + Please note that the `Token` field is deprecated and users should now use `Tokens` instead. If `Token` is used then `Tokens` must be empty. Similarly, if `Tokens` is used then `Token` should be left empty. 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`. @@ -61,3 +81,5 @@ For example, the following memo field is used by the [callbacks middleware](../. ``` You can find more information about other applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). + +Please note that the memo field is always meant to be consumed only on the final destination chain. This means that the transfer module will guarantee that the memo field in the intermediary chains is empty. diff --git a/docs/docs/02-apps/01-transfer/05-events.md b/docs/docs/02-apps/01-transfer/05-events.md index ebd936d1615..3c5cf3782ec 100644 --- a/docs/docs/02-apps/01-transfer/05-events.md +++ b/docs/docs/02-apps/01-transfer/05-events.md @@ -9,45 +9,49 @@ slug: /apps/transfer/events ## `MsgTransfer` -| Type | Attribute Key | Attribute Value | -|--------------|---------------|-----------------| -| ibc_transfer | sender | \{sender\} | -| ibc_transfer | receiver | \{receiver\} | -| ibc_transfer | tokens | \{jsonTokens\} | -| ibc_transfer | memo | \{memo\} | -| message | module | transfer | +| Type | Attribute Key | Attribute Value | +|--------------|-----------------|------------------------| +| ibc_transfer | sender | \{sender\} | +| ibc_transfer | receiver | \{receiver\} | +| ibc_transfer | tokens | \{jsonTokens\} | +| ibc_transfer | memo | \{memo\} | +| ibc_transfer | forwarding_hops | \{jsonForwardingHops\} | +| message | module | transfer | ## `OnRecvPacket` callback -| Type | Attribute Key | Attribute Value | -|-----------------------|---------------|------------------| -| fungible_token_packet | sender | \{sender\} | -| fungible_token_packet | receiver | \{receiver\} | -| fungible_token_packet | tokens | \{jsonTokens\} | -| fungible_token_packet | memo | \{memo\} | -| fungible_token_packet | success | \{ackSuccess\} | -| fungible_token_packet | error | \{ackError\} | -| denomination | trace_hash | \{hex_hash\} | -| denomination | denom | \{jsonDenom\} | -| message | module | transfer | +| Type | Attribute Key | Attribute Value | +|-----------------------|-----------------|------------------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | memo | \{memo\} | +| fungible_token_packet | forwarding_hops | \{jsonForwardingHops\} | +| fungible_token_packet | success | \{ackSuccess\} | +| fungible_token_packet | error | \{ackError\} | +| denomination | trace_hash | \{hex_hash\} | +| denomination | denom | \{jsonDenom\} | +| message | module | transfer | ## `OnAcknowledgePacket` callback -| Type | Attribute Key | Attribute Value | -|-----------------------|-----------------|------------------| -| fungible_token_packet | sender | \{sender\} | -| fungible_token_packet | receiver | \{receiver\} | -| fungible_token_packet | tokens | \{jsonTokens\} | -| fungible_token_packet | memo | \{memo\} | -| fungible_token_packet | acknowledgement | \{ack.String()\} | -| fungible_token_packet | success / error | \{ack.Response\} | -| message | module | transfer | +| Type | Attribute Key | Attribute Value | +|-----------------------|-----------------|------------------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | memo | \{memo\} | +| fungible_token_packet | forwarding_hops | \{jsonForwardingHops\} | +| fungible_token_packet | acknowledgement | \{ack.String()\} | +| fungible_token_packet | success / error | \{ack.Response\} | +| message | module | transfer | ## `OnTimeoutPacket` callback -| Type | Attribute Key | Attribute Value | -|---------|-----------------|-----------------| -| timeout | refund_receiver | \{receiver\} | -| timeout | refund_tokens | \{jsonTokens\} | -| timeout | memo | \{memo\} | -| message | module | transfer | +| Type | Attribute Key | Attribute Value | +|---------|-----------------|------------------------| +| timeout | refund_receiver | \{receiver\} | +| timeout | refund_tokens | \{jsonTokens\} | +| timeout | memo | \{memo\} | +| timeout | forwarding_hops | \{jsonForwardingHops\} | +| message | module | transfer | diff --git a/docs/docs/02-apps/01-transfer/08-authorizations.md b/docs/docs/02-apps/01-transfer/08-authorizations.md index 575f3d7337b..d9e71fac46f 100644 --- a/docs/docs/02-apps/01-transfer/08-authorizations.md +++ b/docs/docs/02-apps/01-transfer/08-authorizations.md @@ -4,6 +4,7 @@ sidebar_label: Authorizations sidebar_position: 8 slug: /apps/transfer/authorizations --- + # `TransferAuthorization` `TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit `MsgTransfer` on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. @@ -17,12 +18,10 @@ The granter may be able to specify the list of addresses that they allow to rece It takes: - a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. - - a `SpendLimit` that specifies the maximum amount of tokens the grantee can transfer. The `SpendLimit` is updated as the tokens are transferred, unless the sentinel value of the maximum value for a 256-bit unsigned integer (i.e. 2^256 - 1) is used for the amount, in which case the `SpendLimit` will not be updated (please be aware that using this sentinel value will grant the grantee the privilege to transfer **all** the tokens of a given denomination available at the granter's account). The helper function `UnboundedSpendLimit` in the `types` package of the `transfer` module provides the sentinel value that can be used. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. - - an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. - - an `AllowedPacketData` list that specifies the list of memo strings that are allowed to be included in the memo field of the packet. If this list is empty, then only an empty memo is allowed (a `memo` field with non-empty content will be denied). If this list includes a single element equal to `"*"`, then any content in `memo` field will be allowed. +- an `AllowedForwarding` list that specifies the combinations of source port ID/channel ID pairs through which the tokens are allowed to be forwarded until final destination. Please note that granters are expected to specify the unwinding route of IBC vouchers if they wish to allow grantees to unwind the vouchers to their native chain (i.e. grantees cannot make use of the `Unwind` flag and must also set the source port ID, channel ID pairs required to unwind the vouchers in the forwarding `Hops` field). Setting a `TransferAuthorization` is expected to fail if: @@ -32,6 +31,7 @@ Setting a `TransferAuthorization` is expected to fail if: - the source channel ID is invalid - there are duplicate entries in the `AllowList` - the `memo` field is not allowed by `AllowedPacketData` +- the forwarding hops do not match any of the combinations specified in `AllowedForwarding` Below is the `TransferAuthorization` message: @@ -54,5 +54,13 @@ type Allocation struct { // allow list of memo strings, an empty list prohibits all memo strings; // a list only with "*" permits any memo string AllowedPacketData []string + // Optional list of allowed combinations of source port ID/channel ID pairs + // through which the tokens are allowed to be forwarded until final + // destination + AllowedForwarding []AllowedForwarding +} + +type AllowedForwarding struct { + Hops []Hop } ``` diff --git a/docs/docs/02-apps/01-transfer/09-client.md b/docs/docs/02-apps/01-transfer/09-client.md index 64ec2bd6ad1..c3799f2fbcf 100644 --- a/docs/docs/02-apps/01-transfer/09-client.md +++ b/docs/docs/02-apps/01-transfer/09-client.md @@ -19,6 +19,34 @@ The `query` commands allow users to query `transfer` state. simd query ibc-transfer --help ``` +#### Transactions + +The `tx` commands allow users to interact with the controller submodule. + +```shell +simd tx ibc-transfer --help +``` + +#### `transfer` + +The `transfer` command allows users to execute cross-chain token transfers from the source port ID and channel ID on the sending chain. + +```shell +simd tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins] [flags] +``` + +Multiple tokens can be transferred on the same transaction by specifying a comma-separated list +of amount and denomination (e.g. `100uatom,100uosmo`) in the `coins` option. + +The additional flags that can be used with the command are: + +- `--packet-timeout-height` to specify the timeout block height in the format `{revision}-{height}`. The default value is `0-0`, which effectively disables the timeout. Timeout height can only be absolute, therefore this option must be used in combination with `--absolute-timeouts` set to true. +- `--packet-timeout-timestamp` to specify the timeout timestamp in nanoseconds. The timeout can be either relative (fromthe current UTC time) or absolute. The default value is 10 minutes (and thus relative). The timeout is disabled when set to 0. +- `--absolute-timeouts` to interpret the timeout timestamp as an aboslute value (when set to true). The default value is false (and thus the timeout timeout is considered relative to current UTC time). +- `--memo` to specify the memo string to be sent along with the transfer packet. If forwarding is used, then the memo string will be carried through the intermediary chains to the final destination. +- `--forwarding` to specify forwarding information in the form of a comma separated list of source port ID/channel ID pairs at each intermediary chain (e.g. `transfer/channel-0,transfer/channel-1`). +- `--unwind` to specify if the tokens must be automatically unwound to there origin chain. This option can be used in combination with `--forwarding` to forward the tokens to the final destination after unwinding. When this flag is true, the `coins` option must specify a single coin. + #### `total-escrow` The `total-escrow` command allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/01-overview.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/01-overview.md new file mode 100644 index 00000000000..fa98a8683bf --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/01-overview.md @@ -0,0 +1,142 @@ +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +slug: /apps/transfer/ics20-v1/overview +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Overview + +:::note Synopsis +Learn about what the token Transfer module is +::: + +## What is the Transfer module? + +Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. + +## Concepts + +### Acknowledgements + +ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). + +A successful receive of a transfer packet will result in a Result Acknowledgement being written +with the value `[]byte{byte(1)}` in the `Response` field. + +An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written +with the error message in the `Response` field. + +### Denomination trace + +The denomination trace corresponds to the information that allows a token to be traced back to its +origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to +the oldest in the timeline of transfers. + +This information is included on the token's base denomination field in the form of a hash to prevent an +unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed +as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`. The human readable denomination +is stored using `x/bank` module's [denom metadata](https://docs.cosmos.network/main/build/modules/bank#denom-metadata) +feature. You may display the human readable denominations by querying balances with the `--resolve-denom` flag, as in: + +```shell +simd query bank balances [address] --resolve-denom +``` + +Each send to any chain other than the one it was previously received from is a movement forwards in +the token's timeline. This causes trace to be added to the token's history and the destination port +and destination channel to be prefixed to the denomination. In these instances the sender chain is +acting as the "source zone". When the token is sent back to the chain it previously received from, the +prefix is removed. This is a backwards movement in the token's timeline and the sender chain is +acting as the "sink zone". + +It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](/architecture/adr-001-coin-source-tracing) to understand the implications and context of the IBC token representations. + +## UX suggestions for clients + +For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: + +### Direct connection + +If the denomination trace contains a single identifier prefix pair (as in the example above), then +the easiest way to retrieve the chain and light client identifier is to map the trace information +directly. In summary, this requires querying the channel from the denomination trace identifiers, +and then the counterparty client state using the counterparty port and channel identifiers from the +retrieved channel. + +A general pseudo algorithm would look like the following: + +1. Query the full denomination trace. +2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the + token. +3. Query the client state using the identifiers pair. Note that this query will return a `"Not +Found"` response if the current chain is not connected to this channel. +4. Retrieve the client identifier or chain identifier from the client state (eg: on + Tendermint clients) and store it locally. + +Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: + +1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` +2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` +3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` +4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` + +Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. + +### Multiple hops + +The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. + +The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. + +Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). + +Thus the proposed solution for clients that the IBC team recommends are the following: + +- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to + perform the queries outlined in the [direct connection](#direct-connection) section to each + relevant chain. By repeatedly following the port and channel denomination trace transfer timeline, + clients should always be able to find all the relevant identifiers. This comes at the tradeoff + that the client must connect to nodes on each of the chains in order to perform the queries. +- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that + could map the denomination trace to the chain path timeline for each token (i.e `origin chain -> +chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in + order to allow clients to optionally verify the path timeline correctness for themselves by + running light clients. If the proofs are not verified, they should be considered as trusted third + parties services. Additionally, client would be advised in the future to use RaaS that support the + largest number of connections between chains in the ecosystem. Unfortunately, none of the existing + public relayers (in [Golang](https://github.com/cosmos/relayer) and + [Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients. + +:::tip +The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. +::: + +## Locked funds + +In some [exceptional cases](/architecture/adr-026-ibc-client-recovery-mechanisms#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. + +To mitigate this, a client update governance proposal can be submitted to update the frozen client +with a new valid header. Once the proposal passes the client state will be unfrozen and the funds +from the associated channels will then be unlocked. This mechanism only applies to clients that +allow updates via governance, such as Tendermint clients. + +In addition to this, it's important to mention that a token must be sent back along the exact route +that it took originally in order to return it to its original form on the source chain (eg: the +Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will +**not** move the token back across its timeline. If a channel in the chain history closes before the +token can be sent back across that channel, then the token will not be returnable to its original +form. + +## Security considerations + +For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC +transfer module needs a subset of the denomination space that only it can create tokens in. + +## Channel Closure + +The IBC transfer module does not support channel closure. diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/02-state.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/02-state.md new file mode 100644 index 00000000000..1d8207b58ef --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/02-state.md @@ -0,0 +1,17 @@ +--- +title: State +sidebar_label: State +sidebar_position: 2 +slug: /apps/transfer/ics20-v1/state +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# State + +The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](/architecture/adr-001-coin-source-tracing). + +- `Port`: `0x01 -> ProtocolBuffer(string)` +- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/03-state-transitions.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/03-state-transitions.md new file mode 100644 index 00000000000..6e31bd5c298 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/03-state-transitions.md @@ -0,0 +1,41 @@ +--- +title: State Transitions +sidebar_label: State Transitions +sidebar_position: 3 +slug: /apps/transfer/ics20-v1/state-transitions +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# State transitions + +## Send fungible tokens + +A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: + +1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: + + - The coins are transferred to an escrow address (i.e locked) on the sender chain. + - The coins are transferred to the receiving chain through IBC TAO logic. + +2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: + + - The coins (vouchers) are burned on the sender chain. + - The coins are transferred to the receiving chain through IBC TAO logic. + +## Receive fungible tokens + +A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: + +1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: + + - The leftmost port and channel identifier pair is removed from the token denomination prefix. + - The tokens are unescrowed and sent to the receiving address. + +2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions: + + - Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information. + - The receiving chain stores the new trace information in the store (if not set already). + - The vouchers are sent to the receiving address. diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/04-messages.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/04-messages.md new file mode 100644 index 00000000000..703054ae1ec --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/04-messages.md @@ -0,0 +1,63 @@ +--- +title: Messages +sidebar_label: Messages +sidebar_position: 4 +slug: /apps/transfer/ics20-v1/messages +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Messages + +## `MsgTransfer` + +A fungible token cross chain transfer is achieved by using the `MsgTransfer`: + +```go +type MsgTransfer struct { + SourcePort string + SourceChannel string + Token sdk.Coin + Sender string + Receiver string + TimeoutHeight ibcexported.Height + TimeoutTimestamp uint64 + Memo string +} +``` + +This message is expected to fail if: + +- `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). +- `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)). +- `Token` is invalid: + - `Amount` is not positive. + - `Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](/architecture/adr-001-coin-source-tracing). +- `Sender` is empty. +- `Receiver` is empty or contains more than 2048 bytes. +- `Memo` contains more than 32768 bytes. +- `TimeoutHeight` and `TimeoutTimestamp` are both zero. + +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`. + +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. + +### Memo + +The memo field was added to allow applications and users to attach metadata to transfer packets. The field is optional and may be left empty. When it is used to attach metadata for a particular middleware, the memo field should be represented as a json object where different middlewares use different json keys. + +For example, the following memo field is used by the [callbacks middleware](../../../04-middleware/02-callbacks/01-overview.md) to attach a source callback to a transfer packet: + +```jsonc +{ + "src_callback": { + "address": "callbackAddressString", + // optional + "gas_limit": "userDefinedGasLimitString", + } +} +``` + +You can find more information about other applications that use the memo field in the [chain registry](https://github.com/cosmos/chain-registry/blob/master/_memo_keys/ICS20_memo_keys.json). diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/05-events.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/05-events.md new file mode 100644 index 00000000000..cea5b596cf1 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/05-events.md @@ -0,0 +1,61 @@ +--- +title: Events +sidebar_label: Events +sidebar_position: 5 +slug: /apps/transfer/ics20-v1/events +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Events + +## `MsgTransfer` + +| Type | Attribute Key | Attribute Value | +|--------------|-----------------|-----------------| +| ibc_transfer | sender | \{sender\} | +| ibc_transfer | receiver | \{receiver\} | +| ibc_transfer | tokens | \{jsonTokens\} | +| ibc_transfer | memo | \{memo\} | +| ibc_transfer | forwarding_hops | `nil` | +| message | module | transfer | + +## `OnRecvPacket` callback + +| Type | Attribute Key | Attribute Value | +|-----------------------|-----------------|-----------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | memo | \{memo\} | +| fungible_token_packet | forwarding_hops | `nil` | +| fungible_token_packet | success | \{ackSuccess\} | +| fungible_token_packet | error | \{ackError\} | +| denomination | trace_hash | \{hex_hash\} | +| denomination | denom | \{jsonDenom\} | +| message | module | transfer | + +## `OnAcknowledgePacket` callback + +| Type | Attribute Key | Attribute Value | +|-----------------------|-----------------|------------------| +| fungible_token_packet | sender | \{sender\} | +| fungible_token_packet | receiver | \{receiver\} | +| fungible_token_packet | tokens | \{jsonTokens\} | +| fungible_token_packet | memo | \{memo\} | +| fungible_token_packet | forwarding_hops | `nil` | +| fungible_token_packet | acknowledgement | \{ack.String()\} | +| fungible_token_packet | success / error | \{ack.Response\} | +| message | module | transfer | + +## `OnTimeoutPacket` callback + +| Type | Attribute Key | Attribute Value | +|---------|-----------------|-----------------| +| timeout | refund_receiver | \{receiver\} | +| timeout | refund_tokens | \{jsonTokens\} | +| timeout | memo | \{memo\} | +| timeout | forwarding_hops | `nil` | +| message | module | transfer | diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/06-metrics.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/06-metrics.md new file mode 100644 index 00000000000..f788429fd10 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/06-metrics.md @@ -0,0 +1,21 @@ +--- +title: Metrics +sidebar_label: Metrics +sidebar_position: 6 +slug: /apps/transfer/ics20-v1/metrics +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Metrics + +The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/learn/advanced/09-telemetry.md). + +| Metric | Description | Unit | Type | +|:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| +| `tx_msg_ibc_transfer` | The total amount of tokens transferred via IBC in a `MsgTransfer` (source or sink chain) | token | gauge | +| `ibc_transfer_packet_receive` | The total amount of tokens received in a `FungibleTokenPacketData` (source or sink chain) | token | gauge | +| `ibc_transfer_send` | Total number of IBC transfers sent from a chain (source or sink) | transfer | counter | +| `ibc_transfer_receive` | Total number of IBC transfers received to a chain (source or sink) | transfer | counter | diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/07-params.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/07-params.md new file mode 100644 index 00000000000..ca3b20a5acd --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/07-params.md @@ -0,0 +1,97 @@ +--- +title: Params +sidebar_label: Params +sidebar_position: 7 +slug: /apps/transfer/ics20-v1/params +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Parameters + +The IBC transfer application module contains the following parameters: + +| Name | Type | Default Value | +| ---------------- | ---- | ------------- | +| `SendEnabled` | bool | `true` | +| `ReceiveEnabled` | bool | `true` | + +The IBC transfer module stores its parameters in its keeper with the prefix of `0x03`. + +## `SendEnabled` + +The `SendEnabled` parameter controls send cross-chain transfer capabilities for all fungible tokens. + +To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: + +- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. +- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. + +:::warning +Doing so will prevent the token from being transferred between any accounts in the blockchain. +::: + +## `ReceiveEnabled` + +The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. + +To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then, depending on the Cosmos SDK version, do one of the following: + +- For Cosmos SDK v0.46.x or earlier, set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/release/v0.46.x/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. +- For Cosmos SDK versions above v0.46.x, set the bank module's `SendEnabled` entry for the denomination to `false` using `MsgSetSendEnabled` as a governance proposal. + +:::warning +Doing so will prevent the token from being transferred between any accounts in the blockchain. +::: + +## Queries + +Current parameter values can be queried via a query message. + + + +```protobuf +// proto/ibc/applications/transfer/v1/query.proto + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} +``` + +To execute the query in `simd`, you use the following command: + +```bash +simd query ibc-transfer params +``` + +## Changing Parameters + +To change the parameter values, you must make a governance proposal that executes the `MsgUpdateParams` message. + + + +```protobuf +// proto/ibc/applications/transfer/v1/tx.proto + +// MsgUpdateParams is the Msg/UpdateParams request type. +message MsgUpdateParams { + // signer address (it may be the address that controls the module, which defaults to x/gov unless overwritten). + string signer = 1; + + // params defines the transfer parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +message MsgUpdateParamsResponse {} +``` diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/08-authorizations.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/08-authorizations.md new file mode 100644 index 00000000000..6ba1de76ac4 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/08-authorizations.md @@ -0,0 +1,60 @@ +--- +title: Authorizations +sidebar_label: Authorizations +sidebar_position: 8 +slug: /apps/transfer/ics20-v1/authorizations +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# `TransferAuthorization` + +`TransferAuthorization` implements the `Authorization` interface for `ibc.applications.transfer.v1.MsgTransfer`. It allows a granter to grant a grantee the privilege to submit `MsgTransfer` on its behalf. Please see the [Cosmos SDK docs](https://docs.cosmos.network/v0.47/modules/authz) for more details on granting privileges via the `x/authz` module. + +More specifically, the granter allows the grantee to transfer funds that belong to the granter over a specified channel. + +For the specified channel, the granter must be able to specify a spend limit of a specific denomination they wish to allow the grantee to be able to transfer. + +The granter may be able to specify the list of addresses that they allow to receive funds. If empty, then all addresses are allowed. + +It takes: + +- a `SourcePort` and a `SourceChannel` which together comprise the unique transfer channel identifier over which authorized funds can be transferred. +- a `SpendLimit` that specifies the maximum amount of tokens the grantee can transfer. The `SpendLimit` is updated as the tokens are transferred, unless the sentinel value of the maximum value for a 256-bit unsigned integer (i.e. 2^256 - 1) is used for the amount, in which case the `SpendLimit` will not be updated (please be aware that using this sentinel value will grant the grantee the privilege to transfer **all** the tokens of a given denomination available at the granter's account). The helper function `UnboundedSpendLimit` in the `types` package of the `transfer` module provides the sentinel value that can be used. This `SpendLimit` may also be updated to increase or decrease the limit as the granter wishes. +- an `AllowList` list that specifies the list of addresses that are allowed to receive funds. If this list is empty, then all addresses are allowed to receive funds from the `TransferAuthorization`. +- an `AllowedPacketData` list that specifies the list of memo strings that are allowed to be included in the memo field of the packet. If this list is empty, then only an empty memo is allowed (a `memo` field with non-empty content will be denied). If this list includes a single element equal to `"*"`, then any content in `memo` field will be allowed. + +Setting a `TransferAuthorization` is expected to fail if: + +- the spend limit is nil +- the denomination of the spend limit is an invalid coin type +- the source port ID is invalid +- the source channel ID is invalid +- there are duplicate entries in the `AllowList` +- the `memo` field is not allowed by `AllowedPacketData` + +Below is the `TransferAuthorization` message: + +```go +func NewTransferAuthorization(allocations ...Allocation) *TransferAuthorization { + return &TransferAuthorization{ + Allocations: allocations, + } +} + +type Allocation struct { + // the port on which the packet will be sent + SourcePort string + // the channel by which the packet will be sent + SourceChannel string + // spend limitation on the channel + SpendLimit sdk.Coins + // allow list of receivers, an empty allow list permits any receiver address + AllowList []string + // allow list of memo strings, an empty list prohibits all memo strings; + // a list only with "*" permits any memo string + AllowedPacketData []string +} +``` diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/09-client.md b/docs/docs/02-apps/01-transfer/10-ICS20-v1/09-client.md new file mode 100644 index 00000000000..d55b8531271 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/09-client.md @@ -0,0 +1,98 @@ +--- +title: Client +sidebar_label: Client +sidebar_position: 9 +slug: /apps/transfer/ics20-v1/client +--- + +:::warning +This document is relevant only for fungible token transfers over channels on v1 of the ICS-20 protocol. +::: + +# Client + +## CLI + +A user can query and interact with the `transfer` module using the CLI. Use the `--help` flag to discover the available commands: + +### Query + +The `query` commands allow users to query `transfer` state. + +```shell +simd query ibc-transfer --help +``` + +#### Transactions + +The `tx` commands allow users to interact with the controller submodule. + +```shell +simd tx ibc-transfer --help +``` + +#### `transfer` + +The `transfer` command allows users to execute cross-chain token transfers from the source port ID and channel ID on the sending chain. + +```shell +simd tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins] [flags] +``` + +The `coins` parameter accepts the amount and denomination (e.g. `100uatom`) of the tokens to be transferred. + +The additional flags that can be used with the command are: + +- `--packet-timeout-height` to specify the timeout block height in the format `{revision}-{height}`. The default value is `0-0`, which effectively disables the timeout. Timeout height can only be absolute, therefore this option must be used in combination with `--absolute-timeouts` set to true. +- `--packet-timeout-timestamp` to specify the timeout timestamp in nanoseconds. The timeout can be either relative (fromthe current UTC time) or absolute. The default value is 10 minutes (and thus relative). The timeout is disabled when set to 0. +- `--absolute-timeouts` to interpret the timeout timestamp as an aboslute value (when set to true). The default value is false (and thus the timeout timeout is considered relative to current UTC time). +- `--memo` to specify the memo string to be sent along with the transfer packet. If forwarding is used, then the memo string will be carried through the intermediary chains to the final destination. + +#### `total-escrow` + +The `total-escrow` command allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. + +```shell +simd query ibc-transfer total-escrow [denom] [flags] +``` + +Example: + +```shell +simd query ibc-transfer total-escrow samoleans +``` + +Example Output: + +```shell +amount: "100" +``` + +## gRPC + +A user can query the `transfer` module using gRPC endpoints. + +### `TotalEscrowForDenom` + +The `TotalEscrowForDenom` endpoint allows users to query the total amount in escrow for a particular coin denomination regardless of the transfer channel from where the coins were sent out. + +```shell +ibc.applications.transfer.v1.Query/TotalEscrowForDenom +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{"denom":"samoleans"}' \ + localhost:9090 \ + ibc.applications.transfer.v1.Query/TotalEscrowForDenom +``` + +Example output: + +```shell +{ + "amount": "100" +} +``` diff --git a/docs/docs/02-apps/01-transfer/10-ICS20-v1/_category_.json b/docs/docs/02-apps/01-transfer/10-ICS20-v1/_category_.json new file mode 100644 index 00000000000..3ea1fff9668 --- /dev/null +++ b/docs/docs/02-apps/01-transfer/10-ICS20-v1/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "ICS20 v1", + "position": 10, + "link": null +} diff --git a/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-dark.png b/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-dark.png new file mode 100644 index 00000000000..3da5c63f6ec Binary files /dev/null and b/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-dark.png differ diff --git a/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-light.png b/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-light.png new file mode 100644 index 00000000000..032919e8177 Binary files /dev/null and b/docs/docs/02-apps/01-transfer/images/forwarding-3-chains-light.png differ