L2 to L1 messaging
Arbitrum's outbox system allows for arbitrary child chain to parent chain contract calls, i.e., messages initiated from the child chain, which eventually resolve in execution on the parent chain. Child-to-parent chain messages (aka "outgoing" messages) bear some things in common with Arbitrum's parent chain to child chain messages, which are "in reverse" though with differences, which we'll explore in this section.
Protocol flow
Messages from child to parent are included in Arbitrum's Rollup state and finalized through the Rollup Protocol. The process follows these steps:
- Message creation on child chain:
- To initiate a child-to-parent chain message, a user or contract calls the
sendTxToL1
method on theArbSys
precompile.
- To initiate a child-to-parent chain message, a user or contract calls the
- Message inclusion in an assertion:
- The message is batched with other transactions and included in a Rollup assertion.
- Assertions are submitted to the Rollup contract on the parent chain and enter the dispute window (~one week).
- Assertion confirmation:
- If the assertion remains unchallenged after the dispute window, the Rollup contract finalizes the assertion.
- The assertion's Merkle root gets posted to the outbox contract on the parent chain.
- Execution on the parent chain:
- Once the assertion is confirmed, anyone can execute the message on the parent chain by proving its inclusion.
- Execution is possible using
Outbox.executeTransaction
, which takes a Merkle proof proving the message exists in the finalized assertion.
Client flow (How to send and execute messages)
Sending a message from a child to parent chain
A contract or user sends a message from the child chain by calling:
ArbSys(100).sendTxToL1(destAddress, calldata);
Executing the message on the parent chain
After the seven-day Challenge period, if the assertion is confirmed, anyone can execute the message on the parent chain.
- Retrieve proof data:
- Call the
constructOutboxProof
method from theNodeInterface
contract to get proof data.
- Call the
We refer to NodeInterface
as a "virtual" contract; its methods are accessible via calls 0x00000000000000000000000000000000000000C8
, but it doesn't live onchain. It isn't a precompile but behaves like a precompile that can't receive calls from other contracts. This approach is a cute trick that lets us provide Arbitrum-specific data without implementing a custom RPC.
- Execute on the parent chain;
- Call
Outbox.executeTransaction
with the proof data to execute the message on the parent chain.
- Call
Protocol design details
Constant overhead for node confirmation
- Calling
confirmNode
on the Rollup contract has constant gas overhead, regardless of the number of messages in the assertion. - This confirmation ensures malicious actors cannot grief the network by submitting assertions with many outgoing messages.
Why child to parent chain messages require manual execution
Unlike retryable tickets, which can execute automatically with pre-funded gas, child-to-parent chain message must undergo manual execution because Ethereum (parent chain) does not support scheduled execution.
However, applications can implement execution markets that allow third parties to execute messages for a fee.
Persistence and expiry
- Child-to-parent chain messages: - Persist indefinitely on the parent chain once included in the outbox.
Parent-to-child chain message lifecycle
Each message progresses through three primary states:
Stage | Description |
---|---|
Posted on child chain | The message is sent via ArbSys.sendTxToL1 . |
Waiting for finalization | The assertion containing the message is in the challenge period (~6.4 days) |
Confirmed and executable on the parent chain | If no fraud proof is submitted, the assertion is confirmed, and the message is available for execution in the outbox. |
Withdrawing Ether
Withdrawing Ether can be done using the ArbSys precompile's withdrawEth
method:
ArbSys(100).withdrawEth{ value: 2300000 }(destAddress)
Upon withdrawing, the Ether balance is burnt on the child chain side and will later be made available on the parent chain side.
ArbSys.withdrawEth
is a convenience function equivalent to calling ArbSys.sendTxToL1
with empty calldataForL1
. Like any other sendTxToL1
call, it will require an additional call to Outbox.executeTransaction
on the parent chain after the dispute period elapses for the user to finalize claiming their funds on the parent chain. Once the withdraw executes (removed from the outbox), the user's Ether balance will receive credit on the parent chain.
The following diagram depicts the process that funds follow during a withdrawal operation.
ERC-20
token withdrawal
Arbitrum has a canonical bridge design and architecture, which we explain in detail in the Token bridging section of Bridging from a parent chain to a child chain article. This section will explain how the Arbitrum canonical bridge works on the child-to-parent chain token bridging.
- Initiation of a child-to-parent chain transfer occurs via the
L2GatewayRouter
contract on the child chain. - The token's gateway contract (
L2ArbitrumGateway
) on the child chain gets called. L2ArbitrumGateway
finally communicates to its corresponding gateway contract on the parent chain using theL1ArbitrumGateway
contract.

For any given gateway pairing, calls have to be initiated through the corresponding router (L2GatewayRouter
), and the gateways must conform to the TokenGateway
interfaces; the TokenGateway
interfaces should be flexible and extensible enough to support any bridging functionality a particular token may require.
Token withdrawals are the most common usage of child-to-parent chain messaging. The standard withdrawal happens as follows (for standard gateway):
- On the child chain, a user calls
L2GatewayRouter.outBoundTransfer
, which callsoutBoundTransfer
onarbSomeERC20Token
's gateway (i.e.,L2ERC20Gateway
). - This call burns arbSomeERC20Token tokens and calls
ArbSys
with an encoded message toL1ERC20Gateway.finalizeInboundTransfer
, which will eventually execute on the parent chain. - After the dispute window expires and the assertion with the user's transaction receives confirmation, a user can call
Outbox.executeTransaction
, which calls the encodedL1ERC20Gateway.finalizeInboundTransfer
message, releasing the user's tokens from theL1ERC20Gateway
contract's escrow.