The Packet relay sending works based in 2 cases (per
[specification](https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay) and [Colin Axnér](https://github.com/colin-axner)'s description):
1. Sender chain is acting as the source zone. The coins are transferred
to an escrow address (i.e locked) on the sender chain and then transferred
to the receiving chain through IBC TAO logic. It is expected that the
receiving chain will mint vouchers to the receiving address.
2. Sender chain is acting as the sink zone. The coins (vouchers) are burned
on the sender chain and then transferred to the receiving chain though IBC
TAO logic. It is expected that the receiving chain, which had previously
sent the original denomination, will unescrow the fungible token and send
it to the receiving address.
Another way of thinking of source and sink zones is through the token's
timeline. 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.
### Example
Assume the following channel connections exist and that all channels use the port ID `transfer`:
- chain `A` has channels with chain `B` and chain `C` with the IDs `channelToB` and `channelToC`, respectively
- chain `B` has channels with chain `A` and chain `C` with the IDs `channelToA` and `channelToC`, respectively
- chain `C` has channels with chain `A` and chain `B` with the IDs `channelToA` and `channelToB`, respectively
These steps of transfer between chains occur in the following order: `A -> B -> C -> A -> C`. In particular:
1.`A -> B`: sender chain is source zone. `A` sends packet with `denom` (escrowed on `A`), `B` receives `denom` and mints and sends voucher `transfer/channelToA/denom` to recipient.
2.`B -> C`: sender chain is source zone. `B` sends packet with `transfer/channelToA/denom` (escrowed on `B`), `C` receives `transfer/channelToA/denom` and mints and sends voucher `transfer/channelToB/transfer/channelToA/denom` to recipient.
3.`C -> A`: sender chain is source zone. `C` sends packet with `transfer/channelToB/transfer/channelToA/denom` (escrowed on `C`), `A` receives `transfer/channelToB/transfer/channelToA/denom` and mints and sends voucher `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom` to recipient.
4.`A -> C`: sender chain is sink zone. `A` sends packet with `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom` (burned on `A`), `C` receives `transfer/channelToC/transfer/channelToB/transfer/channelToA/denom`, and unescrows and sends `transfer/channelToB/transfer/channelToA/denom` to recipient.
The token has a final denomination on chain `C` of `transfer/channelToB/transfer/channelToA/denom`, where `transfer/channelToB/transfer/channelToA` is the trace information.
In this context, upon a receive of a cross-chain fungible token transfer, if the sender chain is the source of the token, the protocol prefixes the denomination with the port and channel identifiers in the following format:
The denomination trace info only needs to be updated when token is received:
- Receiver is **source** chain: The receiver created the token and must have the trace lookup already stored (if necessary _ie_ native token case wouldn't need a lookup).
- Receiver is **not source** chain: Store the received info. For example, during step 1, when chain `B` receives `transfer/channelToA/denom`.
One final remark is that the `FungibleTokenPacketData` will remain the same, i.e with the prefixed full denomination, since the receiving chain may not be an SDK-based chain.
### Coin Changes
The coin denomination validation will need to be updated to reflect these changes. In particular, the denomination validation
function will now:
- Accept slash separators (`"/"`) and uppercase characters (due to the `HexBytes` format)
Additional validation logic, such as verifying the length of the hash, the may be added to the bank module in the future if the [custom base denomination validation](https://github.com/cosmos/cosmos-sdk/pull/6755) is integrated into the SDK.
### Positive
- Clearer separation of the source tracing behaviour of the token (transfer prefix) from the original
`Coin` denomination
- Consistent validation of `Coin` fields (i.e no special characters, fixed max length)
- Cleaner `Coin` and standard denominations for IBC
- No additional fields to SDK `Coin`
### Negative
- Store each set of tracing denomination identifiers on the `ibc-transfer` module store
- Clients will have to fetch the base denomination every time they receive a new relayed fungible token over IBC. This can be mitigated using a map/cache for already seen hashes on the client side. Other forms of mitigation, would be opening a websocket connection subscribe to incoming events.
### Neutral
- Slight difference with the ICS20 spec
- Additional validation logic for IBC coins on the `ibc-transfer` module
- Additional genesis fields
- Slightly increases the gas usage on cross-chain transfers due to access to the store. This should