SuperchainETHBridge

Table of Contents

Overview

The SuperchainETHBridge is a predeploy contract that facilitates cross-chain ETH bridging within the Superchain interop set. It serves as an abstraction layer on top of the L2toL2CrossDomainMessenger specifically designed for native ETH transfers between chains. The contract integrates with the ETHLiquidity contract to manage native ETH liquidity across chains, ensuring seamless cross-chain transfers of native ETH.

The SuperchainETHBridge only handles native ETH cross-chain transfers. For interoperable ETH withdrawals, see the ETHLockbox specification.

Constants

NameValue
SuperchainETHBridge Address0x4200000000000000000000000000000000000024

Definitions

ETH Bridging

ETH Bridging refers to the process of transferring native ETH from one chain to another within the Superchain interop set. This process involves burning ETH on the source chain and minting an equivalent amount on the destination chain.

ETH Liquidity

ETH Liquidity refers to the availability of native ETH on a particular chain. The ETHLiquidity contract manages this liquidity by providing a mechanism to burn and mint ETH as needed for cross-chain transfers.

Cross-Chain Message

A Cross-Chain Message is a message sent from one chain to another using the L2ToL2CrossDomainMessenger. In the context of the SuperchainETHBridge, these messages contain instructions to relay ETH to a recipient on the destination chain.

Source Chain

The Source Chain is the chain from which a user initiates an ETH transfer. On this chain, ETH is burned from the user's account and a cross-chain message is sent to the destination chain.

Destination Chain

The Destination Chain is the chain to which ETH is being transferred. On this chain, ETH is sent to the recipient's account based on the cross-chain message received from the source chain.

Assumptions

aSEB-001: L2ToL2CrossDomainMessenger properly delivers messages

We assume that the L2ToL2CrossDomainMessenger contract properly and faithfully delivers messages between chains, maintaining the integrity and authenticity of the message contents.

Mitigations

  • Extensive testing of the L2ToL2CrossDomainMessenger contract
  • Audits of the messaging protocol
  • Monitoring of cross-chain message delivery

aSEB-002: ETHLiquidity contract maintains sufficient liquidity

We assume that the ETHLiquidity contract maintains sufficient liquidity to fulfill all valid ETH minting requests. This is ensured by initializing the contract with type(uint128).max wei.

Mitigations

  • Total ETH supply is much less than the initial balance of the ETHLiquidity contract
  • Contract is initially initialized with type(uint128).max wei and can hold up to type(uint256).max wei to prevent balance overflow

aSEB-003: SafeSend correctly transfers ETH to recipients

We assume that the SafeSend mechanism correctly transfers ETH to recipients without reverting for valid addresses.

Mitigations

  • Extensive testing of the SafeSend mechanism
  • Audits of the ETH transfer logic

aSEB-004: ETH sent to an unauthorized chain is lost

We assume that users send ETH only to chains whose portals this chain's ETHLockbox authorizes. ETH sent to any other chain ID cannot be relayed or refunded until this chain's ETHLockbox authorizes that chain's portal. sendMessage checks only that the destination is not this chain, and relayUndeliveredMessage reverts for a portal that the ETHLockbox does not authorize.

Mitigations

  • Applications and wallets should check that the destination chain is in this chain's dependency set before sending

Invariants

iSEB-001: ETH sent equals ETH received

The amount of ETH sent from the source chain must equal the amount of ETH received on the destination chain, or refunded on the source chain, for any given cross-chain transfer.

Impact

Severity: Critical

If this invariant is broken, users could receive more or less ETH than they sent, leading to inflation or loss of funds.

Dependencies

iSEB-002: Only authorized contracts can call relayETH

The relayETH function must only be callable by the L2ToL2CrossDomainMessenger contract, and the cross-domain sender must be the SuperchainETHBridge contract on the source chain.

Impact

Severity: Critical

If this invariant is broken, unauthorized parties could mint ETH on the destination chain without burning an equivalent amount on the source chain, leading to inflation.

Dependencies

iSEB-003: ETH cannot be sent to the zero address

The sendETH function must revert if the recipient address is the zero address.

Impact

Severity: High

If this invariant is broken, ETH could be sent to the zero address, effectively burning it without the possibility of recovery.

Dependencies

None

iSEB-004: ETH is refunded only for expired sends, at most once

refundETH must pay out only for a send whose message is marked expired, at most once per message, only the amount that the send's message committed to, and only to the address that called sendETH, when that address calls refundETH.

Impact

Severity: Critical

If this invariant is broken, ETH could be both delivered on the destination chain and refunded on the source chain, leading to inflation.

Dependencies

iSEB-005: Each send pays out at most once

Across all chains, each sendETH must pay out at most once, through relayETH on the destination chain or refundETH on the source chain. The payout must equal the amount burned.

Impact

Severity: Critical

If this invariant is broken, the same ETH could be paid out on both chains, or twice on one, leading to inflation.

Dependencies

Function Specification

sendETH

Deposits the msg.value of ETH into the ETHLiquidity contract and sends a cross-chain message to the specified _chainId to call relayETH with the _to address as the recipient and the msg.value as the amount.

function sendETH(address _to, uint256 _chainId) external payable returns (bytes32 msgHash_);
  • MUST accept ETH via msg.value.
  • MUST revert if the _to address is the zero address.
  • MUST revert with SuperchainETHBridge_SenderIsMessenger if msg.sender is the L2ToL2CrossDomainMessenger. A relayed message that called sendETH would make the messenger the sender, and it could never claim a refund. The L2CrossDomainMessenger stays allowed: a message from L1 that reverted here would keep its ETH there. Its sends cannot be refunded to their sender on L1; see refundETH.
  • MUST transfer msg.value of ETH from the msg.sender to the ETHLiquidity contract by calling ETHLiquidity.burn{value: msg.value}().
  • MUST create a cross-chain message to the SuperchainETHBridge contract on the destination chain with the following parameters:
    • _chainId: The destination chain ID.
    • message: An encoded call to relayETH(msg.sender, _to, msg.value).
  • MUST return the message hash msgHash_ generated by the L2ToL2CrossDomainMessenger.
  • MUST emit a SendETH event with the msg.sender, _to, msg.value, and _chainId.

relayETH

Withdraws ETH from the ETHLiquidity contract equal to the _amount and sends it to the _to address.

function relayETH(address _from, address _to, uint256 _amount) external;
  • MUST revert if called by any address other than the L2ToL2CrossDomainMessenger.
  • MUST revert if the cross-domain sender is not the SuperchainETHBridge contract on the source chain.
  • MUST withdraw _amount of ETH from the ETHLiquidity contract by calling ETHLiquidity.mint(_amount).
  • MUST transfer the _amount of ETH to the _to address using new SafeSend{value: _amount}(_to).
  • MUST emit a RelayETH event with the _from address, _to address, _amount, and source chain ID.

refundETH

Returns the ETH of a send whose message expired: its destination chain never relayed it, and never can.

function refundETH(uint256 _destination, uint256 _nonce, address _to, uint256 _amount) external;

mapping(bytes32 => bool) public refunded;
  • MUST compute the message hash of the send from its arguments, with this chain as the source and the SuperchainETHBridge as both sender and target of a relayETH(msg.sender, _to, _amount) call.
  • MUST revert with SuperchainETHBridge_MessageNotExpired if L2ToL2CrossDomainMessenger.expiredMessages(messageHash) is false. This covers a caller that did not send it.
  • MUST revert with SuperchainETHBridge_AlreadyRefunded if refunded[messageHash] is true.
  • MUST set refunded[messageHash] to true before transferring ETH.
  • MUST withdraw _amount of ETH from the ETHLiquidity contract by calling ETHLiquidity.mint(_amount).
  • MUST transfer the _amount of ETH to msg.sender using new SafeSend{value: _amount}(msg.sender).
  • MUST emit a RefundETH event with msg.sender, _amount, and the message hash.

Only the msg.sender of sendETH can claim its refund, and the ETH goes back to it. A contract that called sendETH on behalf of someone else calls refundETH itself and passes the ETH on. Two kinds of sender cannot get their ETH back:

  • A send made from L1 through the L2CrossDomainMessenger. A refundETH call made the same way matches the send's hash, but pays the L2CrossDomainMessenger, and the ETH stays there. A sender on L1 should deposit through the OptimismPortal and call sendETH from its own address, or send through a contract on L2.
  • A contract that has no way to call refundETH.

While ETHLiquidity is paused, sendETH, relayETH and refundETH revert, because burn and mint do. Relays and refunds can be retried after the unpause. A send whose message expires during the pause can be refunded after the unpause.

Events

SendETH event

MUST be triggered when sendETH is called.

event SendETH(address indexed from, address indexed to, uint256 amount, uint256 destination);

RelayETH event

MUST be triggered when relayETH is called.

event RelayETH(address indexed from, address indexed to, uint256 amount, uint256 source);

RefundETH event

MUST be triggered when refundETH is called.

event RefundETH(address indexed from, uint256 amount, bytes32 indexed messageHash);