Skip to main content

Bridging ERC20 Tokens

Introduction

The ERC20 bridge basically locks the tokens on the native chain, and creates a wrapped version of them on the destination. There are 3 possible flows, depending on the different situations that may occur when bridging tokens:

Going from a token’s native chain to a non-native chain: This would be the first scenario we would face as users. We would want to bridge a token that we have on chain A to a chain B (where the token doesn’t exist). So the router on chain A will lock the tokens on chain A, and ask the router on chain B to create a wrapped version of the token (If it doesn’t exist already), with similar name (Adding the word Wrapped at the beginning), symbol (Adding the letter "w" at the beginning) and decimals on chain B. Then it will mint the recipient address the stated amount of the wrapped token. There’s a special case for the native coin, which will behave in the same way, if the user wants to bridge native coin, the native coin will be locked on the source chain, and then a wrapped ERC20 token will be created on the target non-native chain.

Going from a token’s non-native chain to a native chain: This scenario would occur when the user has some wrapped tokens on chain B, and wants to send them back to chain A. So, the router would burn the wrapped token amount from the user on chain B, and will unlock the token’s amount on chain A.

And going from a token’s non-native chain to a non-native chain: Finally, the last scenario would occur when the user tries to send a wrapped token from chain B to chain C, where the original token doesn’t exist either. So, the bridge would burn the token’s amount from the user on chain B, would create a wrapped version of the token in chain C (If it doesn’t exist already), and would mint the amount required to the recipient address. Chain C would behave exactly as chain B, both chains are considered non-native chains for that token, so user should be able to also send from chain C to chain A if desired.

When an egress operation is performed, the bridge identifies which of the previous stated flows is the one taking place, and creates an instruction payload to be sent to the destination chain's ERC20 bridge contract. This payload is then sent using the Messaging Protocol. When the deliver function of the messaging protocol is called, the target chain's ERC20 bridge contract gets the instructions and acts accordingly. Refer to the deliver explanation on the teleport contract section for details on how to call the deliver and, by doing so, claiming the tokens on the target chain.

How to bridge ERC20 tokens

In order to bridge ERC20 tokens from a source chain to a target chain, there are two functions that can be used. The egress, and the egressWithPermit.

egress

This function allows to send the desired ERC20 tokens or native coin amount to the desired targetChain, using the messaging protocol's teleport contract.

function egress(
uint8 targetChainId_,
address feeToken_,
address token_,
uint256 amount_,
bytes calldata receiver_,
DeliveryFeeData calldata deliveryFeeData_
) public payable
targetChainId_The Messaging Protocol Chain id of the destination chain
feeToken_Address of the token the user is paying fee in. Use address(0) if the intention is to pay with native coin
token_Address of the token to bridge, or address(0) if bridging native currency
amount_Amount of the bridged tokens
receiver_Address who will receive the tokens on the destination chain
deliveryFeeData_Object holding data necessary for deducting the claiming costs from msg.value to delivery agent. Used for the auto claim feature, no need to provide it if the auto claim feature won't be used.

egressWithPermit

This function is similar to the above mentioned egress function (in fact, it ends up calling it), but allows to take advantage of the EIP2612 permit. It basically receives the same parameters than the above one, but adding the permit needed params:

function egress(
uint8 targetChainId_,
address feeToken_,
address token_,
uint256 amount_,
bytes calldata receiver_,
DeliveryFeeData calldata deliveryFeeData_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) public payable
targetChainId_The Messaging Protocol Chain id of the destination chain
feeToken_Address of the token the user is paying fee in. Use address(0) if the intention is to pay with native coin
token_Address of the token to bridge, or address(0) if bridging native currency
amount_Amount of the bridged tokens
receiver_Address who will receive the tokens on the destination chain
deliveryFeeData_Object holding data necessary for deducting the claiming costs from msg.value to delivery agent. Used for the auto claim feature, no need to provide it if the auto claim feature won't be used.
deadline_A timestamp in the future stating the deadline for the provided permit
v_The recovery id of the permit's ECDSA signature
r_The first output of the permit's ECDSA signature
s_The second output of the permit's ECDSA signature