# IBC Token Transfer
Transferring tokens between chains is both a common requirement and a significant technical challenge when two chains are incompatible. A convenient solution for moving tokens between chains is essential.
In this section, you will explore how a fungible token transfer can be done with IBC.
Having looked at IBC's transport, authentication, and ordering layer (IBC/TAO), you can now take a look at ICS-20 (opens new window). ICS-20 describes fungible token transfers.
Fungibility refers to an instance in which a token is interchangeable with other instances of that token or not. Fungible tokens can be exchanged and replaced.
There are many use cases involving token transfers on blockchains, like the tokenization of assets holding value or initial coin offerings (ICOs) to finance blockchain projects. IBC makes it possible to transfer tokens and other digital assets between (sovereign) chains, both fungible and non-fungible tokens. For example, fungible token transfers allow you to build applications relying on cross-chain payments and token exchanges. Therefore, IBC frees up great potential for cross-chain Decentralized Finance (DeFi) applications by offering a technically reliable cross-chain interoperability protocol that is compatible with digital assets on multiple networks.
The corresponding implementation (opens new window) is a module on the application level.
Look at the picture above. You can see two chains, A and B. You also see there is a channel connecting both chains.
How can tokens be transferred between chains and channels?
To understand the application logic for a token transfer, first, you have to determine the source chain:
Then the application logic can be summarized:
Shortly you will see the corresponding code. Now again have a look at a transfer from source to sink:
Above the source is chain A. The source channel is channel-2 and the destination channel is channel-40. The token denominations are represented as {Port}/{Channel}/{denom}
(or rather their IBC denom representation on chain). The prefixed port and channel pair indicate which channel the funds were previously sent through. You see transfer/channel-... because the transfer module will bind to a port, which is named transfer. If chain A sends 100 ATOM tokens, chain B will receive 100 ATOM tokens and append the destination prefix port/channel-id. So chain B will mint those 100 ATOM tokens as ibc/<hash of transfer/channel-40/uatom>. The channel-id will be increased sequentially per channel on a given connection.
We can send assets (or their IBC voucher representation) in multiple hops across multiple chains. Every single time the path will be prepended with the port/channel-id/... prefix.
When sending this IBC denom (having had multiple hops) back to its source chain, for every hop back one port/channel-id/... prefix will be taken off. This results in a return to the original denom if all the hops are reversed.
If the tokens are sent back from the same channel as they were received:
Chain A will "un-escrow" 100 ATOM tokens, thus, the prefix will be removed. Chain B will burn transfer/channel-40/atoms.
The prefix determines the source chain. If the module sends the token from another channel, chain B is the source chain and chain A mints new tokens with a prefix instead of un-escrowing ATOM tokens. You can have different channels between two chains, but you cannot transfer the same token across different channels back and forth. If {denom}
contains /
, then it must also follow the ICS-20 form, which indicates that this token has a multi-hop record. This requires that the character /
is prohibited in non-IBC token denomination names.
You already know that an application needs to implement the IBC Module Interface (opens new window), so have a look at the implementation for the token transfer (opens new window), e.g. for OnChanOpenInit
:
OnChanOpenAck
, OnChanOpenConfirm
, OnChanCloseInit
, and OnChanCloseConfirm
will do (almost) no checks.
# Transfer packet flow
You have seen an introduction to the application packet flow in the section on channels. This section will analyze this packet flow for the specific case of the transfer module.
# Sending a transfer packet
After a channel is established, the module can start sending and receiving packets.
So where does the module send a token? Take a look at the msg_server.go (opens new window) of the token transfer module:
There you see SendTransfer
, which implements the application logic after checking if the sender is a source or sink chain (opens new window):
Take a look at the type definition of a token packet (opens new window) before diving further into the code:
An optional memo field was recently added to the packet definition. More details on the motivation, use cases, and consequences can be found in the accompanying blog post (opens new window).
# Receiving a transfer packet
A relayer will then pick up the SendPacket
event and submit a MsgRecvPacket
on the destination chain.
This will trigger an OnRecvPacket
callback that will decode a packet and apply the transfer token application logic:
Observe in the previous example how we redirect to the module keeper's OnRecvPacket
method and are constructing the acknowledgement to be sent back.
# Acknowledging or timing out packets
A useful exercise is to try to find and analyze the code corresponding to this. The place to start is the packet callbacks, usually defined in a file like module_ibc.go
or ibc_module.go
.
When a packet times out, the submission of a MsgTimeout
is essential to get the locked funds unlocked again. As an exercise, try to find the code where this is executed.
To summarize, this section has explored:
- How IBC provides a reliable solution to the technical challenge of transferring fungible and non-fungible tokens between two different blockchains, freeing up great potential for cross-chain Decentralized Finance (DeFi) applications.
- How the process for transferring value differs based on whether or not the IBC tokens are native to the source chain, or whether or not they are being sent on a channel they were previously received on.