ERC-20 token bridging
The Arbitrum protocol itself technically has no native notion of any token standards, and gives no built-in advantage or special recognition to any particular token bridge. In this page we describe the "canonical bridge", which was implemented by Offchain Labs, and should be the primary bridge most users and applications use; it is (effectively) a decentralized app (dApp) with contracts on both Ethereum (parent chain) and Arbitrum (child chain) that leverages Arbitrum's cross-chain message passing system to achieve basic desired token-bridging functionality. We recommend that you use it!
Design rationale
In our token bridge design, we use the term "gateway" as per this proposal; i.e., one of a pair of contracts on two different domains (i.e., Ethereum and an Arbitrum chain), used to facilitate cross-domain asset transfers.
We now describe some core goals that motivated the design of our bridging system.
Custom gateway functionality
For many ERC-20
tokens, "standard" bridging functionality is sufficient, which entails the following: a token contract on Ethereum is associated with a "paired" token contract on Arbitrum.
Depositing a token entails escrowing some amount of the token in an parent chain bridge contract, and minting the same amount at the paired token contract on a child chain. On the child chain, the paired contract behaves much like a normal ERC-20
token contract. Withdrawing entails burning some amount of the token in the child chain contract, which then can later be claimed from the parent chain bridge contract.
Many tokens, however, require custom gateway systems, the possibilities of which are hard to generalize, e.g.,:
- Tokens which accrue interest to their holders need to ensure that the interest is dispersed properly across layers, and doesn't simply accrue to the bridge contracts
- Our cross-domain
WETH
implementations requires tokens be wrapped and unwrapped as they move across layers.
Thus, our bridge architecture must allow not just the standard deposit and withdraw functionalities, but for new, custom gateways to be dynamically added over time.
Canonical child chain representation per parent chain token contract
Having multiple custom gateways is well and good, but we also want to avoid a situation in which a single parent chain token that uses our bridging system can be represented at multiple addresses/contracts on the child chain as this adds significant friction and confusion for users and developers. Thus, we need a way to track which parent chain token uses which gateway, and in turn, to have a canonical address oracle that maps the tokens addresses across the Ethereum and Arbitrum domains.
Canonical token bridge implementation
With this in mind, we provide an overview of our token bridging architecture.
Our architecture consists of three types of contracts:
- Asset contracts: These are the token contracts themselves, i.e., an
ERC-20
on the parent chain and it's counterpart on Arbitrum. - Gateways: Pairs of contracts (one on the parent chain, one on the child chain) that implement a particular type of cross-chain asset bridging.
- Routers: Exactly two contracts (one on the parent chain, one on the child chain) that route each asset to its designated gateway.
All Ethereum to Arbitrum token transfers are initiated via the router contract on the parent chain, the L1GatewayRouter
contract. L1GatewayRouter
forwards the token's deposit call to the appropriate gateway contract on the parent chain, the L1ArbitrumGateway
contract. L1GatewayRouter
is responsible for mapping the parent chain token addresses to L1Gateway contracts, thus acting as a parent/child chain address oracle and ensuring each token corresponds to only one gateway. The L1ArbitrumGateway
then communicates to its counterpart gateway contract on the child chain, the L2ArbitrumGateway
contract (typically/expectedly via retryable tickets).

Similarly, Arbitrum to Ethereum transfers are initiated via the router contract on the child chain, the L2GatewayRouter
contract, which calls the token's gateway contract on the child chain, the L2ArbitrumGateway
contract, which in turn communicates to its corresponding gateway contract on the parent chain, the L1ArbitrumGateway
contract (typically/expectedly via sending child-to-parent messages to the outbox).

For any given gateway pairing, we require that calls be initiated through the corresponding router (L1GatewayRouter
or L2GatewayRouter
), and that the gateways conform to the TokenGateway
interfaces; the TokenGateway
interfaces should be flexible and extensible enough to support any bridging functionality a particular token may require.
The standard ERC-20
gateway
By default, any ERC-20
token on a parent chain that isn't registered to a gateway can be permissionlessly bridged through the StandardERC20Gateway
.
You can use the bridge UI or follow the instructions in How to bridge tokens via Arbitrum’s standard ERC-20 gateway to bridge a token to a child chain via this gateway.
Example: Standard Arb-ERC-20 deposit and withdraw
To help illustrate what this all looks like in practice, let's go through the steps of what depositing and withdrawing SomeERC20Token
via our standard ERC-20
gateway looks like. Here, we're assuming that SomeERC20Token
has already been registered in the L1GatewayRouter
to use the standard ERC-20
gateway.
Deposits
- A user calls
L1GatewayRouter.outboundTransferCustomRefund
[1] (withSomeERC20Token
's parent chain address as an argument). L1GatewayRouter
looks upSomeERC20Token
's gateway, and finds that it's the standardERC-20
gateway (theL1ERC20Gateway
contract).L1GatewayRouter
callsL1ERC20Gateway.outboundTransferCustomRefund
, forwarding the appropriate parameters.L1ERC20Gateway
escrows the tokens sent and creates a retryable ticket to triggerL2ERC20Gateway
'sfinalizeInboundTransfer
method on the child chain.L2ERC20Gateway.finalizeInboundTransfer
mints the appropriate amount of tokens at thearbSomeERC20Token
contract on the child chain.
❗️ [1] Please keep in mind that some older custom gateways might not have outboundTransferCustomRefund
implemented and L1GatewayRouter.outboundTransferCustomRefund
does not fallback to outboundTransfer
. In those cases, please use function L1GatewayRouter.outboundTransfer
.
Note that arbSomeERC20Token
is an instance of StandardArbERC20, which includes bridgeMint
and bridgeBurn
methods only callable by the L2ERC20Gateway
.
Withdrawals
- On Arbitrum, a user calls
L2GatewayRouter.outBoundTransfer
, which in turn callsoutBoundTransfer
on arbSomeERC20Token's gateway (i.e., L2ERC20Gateway). - This burns
arbSomeERC20Token
tokens, and callsArbSys
with an encoded message toL1ERC20Gateway.finalizeInboundTransfer
, which will be eventually executed on the parent chain. - After the dispute window expires and the assertion with the user's transaction is confirmed, a user can call
Outbox.executeTransaction
, which in turn calls the encodedL1ERC20Gateway.finalizeInboundTransfer
message, releasing the user's tokens from theL1ERC20Gateway
contract's escrow.
The Arbitrum generic-custom gateway
Just because a token has requirements beyond what are offered via the standard ERC-20
gateway, that doesn't necessarily mean that a unique gateway needs to be tailor-made for the token in question. Our generic-custom gateway is designed to be flexible enough to be suitable for most (but not necessarily all) custom fungible token needs. As a general rule:
If your custom token has the ability to increase its supply (i.e., mint) directly on the child chain, and you want the child chain-minted tokens be withdrawable back to the parent chain and recognized by the parent chain contract, it will probably require its own special gateway. Otherwise, the generic-custom gateway is likely the right solution for you!
Some examples of token features suitable for the generic-custom gateway:
- A child chain token contract upgradable via a proxy
- A child chain token contract that includes address whitelisting/blacklisting
- The deployer determines the address of the child chain token contract
Setting up your token with the generic-custom gateway
Follow the following steps to get your token set up to use the generic-custom gateway. You can also find more detailed instructions in the page How to bridge tokens via Arbitrum’s generic-custom gateway.
0. Have a parent chain token
Your token on the parent chain should conform to the ICustomToken interface (see TestCustomTokenL1
for an example implementation). Crucially, it must have an isArbitrumEnabled
method in its interface.
1. Deploy your token on Arbitrum
Your token should conform to the minimum IArbToken
interface; i.e., it should have bridgeMint
and bridgeBurn
methods only callable by the L2CustomGateway
contract, and the address of its corresponding Ethereum token accessible via l1Address
. For an example implementation, see L2GatewayToken
.
If you want your token to be compatible out of the box with all the tooling available (e.g., the Arbitrum bridge), we recommend that you keep the implementation of the IArbToken interface as close as possible to the L2GatewayToken implementation example.
For example, if an allowance check is added to the bridgeBurn()
function, the token will not be easily withdrawable through the Arbitrum bridge UI, as the UI does not prompt an approval transaction of tokens by default (it expects the tokens to follow the recommended L2GatewayToken
implementation).
2. Register your token on the parent chain to your token on the child chain via the L1CustomGateway
contract
Have your parent chain token's contract make an external call to L1CustomGateway.registerTokenToL2
. This registration can alternatively be performed as a chain-owner registration via an Arbitrum DAO proposal.
3. Register your token on the parent chain to the L1GatewayRouter
After your token's registration to the generic-custom gateway is complete, have your parent chain token's contract make an external call to L1GatewayRouter.setGateway
; this registration can also alternatively be performed as a chain-owner registration via an Arbitrum DAO proposal.
If you have questions about your custom token needs, feel free to reach out on our Discord server.
Other flavors of gateways
Note that in the system described above, one pair of gateway contracts handles the bridging of many ERC-20
's; i.e., many ERC-20
's on the parent chain are each paired with their own ERC-20
's on Arbitrum via a single gateway contract pairing. Other gateways may well bear different relations with the contracts that they bridge.
Take our wrapped Ether implementation for example: here, a single WETH
contract on the parent chain is connected to a single WETH
contract on the child chain. When transferring WETH
from one domain to another, the parent/child chain gateway architecture is used to unwrap the WETH
on domain A, transfer the now-unwrapped Ether, and then re-wrap it on domain B. This ensures that WETH
can behave on Arbitrum the way users are used to it behaving on Ethereum, while ensuring that all WETH
tokens are always fully collateralized on the layer in which they reside.
No matter the complexity of a particular token's bridging needs, a gateway can in principle be created to accommodate it within our canonical bridging system.
You can find an example of implementation of a custom gateway in the page How to bridge tokens via a custom gateway.
Demos
Our How to bridge tokens section provides example of interacting with Arbitrum's token bridge via the Arbitrum SDK.
A word of caution on bridges (aka, "I've got a bridge to sell you")
Cross chain bridging is an exciting design space; alternative bridge designs can potentially offer faster withdrawals, interoperability with other chains, different trust assumptions with their own potentially valuable UX tradeoffs, etc. They can also potentially be completely insecure and/or outright scams. Users should treat other, non-canonical bridge applications the same way they treat any application running on Arbitrum, and exercise caution and due diligence before entrusting them with their value.