L2StandardBridge
Table of Contents
Overview
The L2StandardBridge enables ETH and ERC20 token transfers between Ethereum L1 and an OP Stack L2 chain. It burns L1-native tokens on L2 when withdrawing to L1 and mints them when finalizing deposits from L1. For L2-native tokens, it escrows them when withdrawing to L1 and releases them when finalizing deposits from L1.
Definitions
OptimismMintableERC20
An ERC20 token that implements the IOptimismMintableERC20 or ILegacyMintableERC20 interface, allowing the bridge to mint and burn tokens. These tokens are native to L1 and have a corresponding L2 representation that can be minted/burned by the bridge.
Native L2 Token
An ERC20 token that is native to the L2 chain and does not implement the OptimismMintableERC20 interface. These tokens are escrowed in the bridge contract when withdrawn to L1 and released when deposits are finalized from L1.
Assumptions
a01-001: L1StandardBridge is trusted
The L1StandardBridge contract on L1 is trusted to only send valid finalization messages for legitimate deposits.
Mitigations
- The L1StandardBridge address is set during initialization and cannot be changed
- Cross-chain messages are authenticated through the L2CrossDomainMessenger
a01-002: L2CrossDomainMessenger is trusted
The L2CrossDomainMessenger accurately validates cross-chain messages and correctly identifies the sender.
Mitigations
- The messenger is a system predeploy contract maintained by the protocol
- Message authentication uses the xDomainMessageSender mechanism
a01-003: OptimismMintableERC20 tokens correctly implement mint and burn
OptimismMintableERC20 tokens correctly implement the mint and burn functions and accurately report their remote token address.
Mitigations
- Token pair validation checks that the remote token matches the token's reported remoteToken or l1Token
- Tokens must implement the IOptimismMintableERC20 or ILegacyMintableERC20 interface
Invariants
i01-001: Users who deposit assets on L1 receive them on L2
Users who successfully deposit ETH or ERC20 tokens through the L1 bridge always receive the corresponding assets on L2 when the deposit is finalized within a bounded time period (less than 1 day under normal operation).
Impact
Severity: Critical
If violated, users lose their assets permanently as the L1 assets are locked or burned but the L2 assets are never received.
i01-002: Users who withdraw assets on L2 can claim them on L1
Users who successfully initiate a withdrawal on L2 can always claim the corresponding assets on L1 after the challenge period, provided the withdrawal is properly finalized on L1.
Impact
Severity: Critical
If violated, users lose their assets permanently as the L2 assets are burned or escrowed but the L1 assets cannot be claimed.
i01-003: One-to-one custody across chains
For each bridged asset amount, exactly one of the following holds at any time: it is held on L1 by the bridge (locked or in original form) or it is represented on L2 (minted or in original form). Transitions between these states occur only through the canonical flows: a valid deposit locks or burns the asset on L1 and is paired with a mint or release on L2; a valid withdrawal burns or escrows the asset on L2 and is paired with a release or mint on L1. No other mechanism may create or release representations.
Impact
Severity: Critical
If violated, attackers could mint arbitrary tokens on L2 without depositing the corresponding L1 tokens, or drain the bridge by withdrawing more than was deposited, breaking the 1:1 correspondence between L1 and L2 assets.
Function Specification
initialize
Initializes the L2StandardBridge contract with the L1 bridge address.
Parameters:
_otherBridge: Address of the L1StandardBridge contract
Behavior:
- MUST set the messenger to the L2CrossDomainMessenger predeploy at 0x4200000000000000000000000000000000000007
- MUST set the otherBridge to the provided L1StandardBridge address
- MUST revert if called more than once
receive
Allows EOAs to bridge ETH by sending directly to the bridge contract.
Behavior:
- MUST revert if caller is not an externally owned account
- MUST initiate an ETH withdrawal to the sender's address on L1
- MUST use RECEIVE_DEFAULT_GAS_LIMIT (200,000) as the minimum gas limit
- MUST emit WithdrawalInitiated and ETHBridgeInitiated events
withdraw
Initiates a withdrawal from L2 to L1 for the caller.
Parameters:
_l2Token: Address of the L2 token to withdraw (or 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 for ETH)_amount: Amount of the token to withdraw_minGasLimit: Minimum gas limit for the withdrawal message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST revert if caller is not an externally owned account
- MUST call _initiateWithdrawal with msg.sender as both sender and recipient
- MUST emit WithdrawalInitiated and ETHBridgeInitiated or ERC20BridgeInitiated events
withdrawTo
Initiates a withdrawal from L2 to L1 to a specified recipient on L1.
Parameters:
_l2Token: Address of the L2 token to withdraw (or 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 for ETH)_to: Address to receive the assets on L1_amount: Amount of the token to withdraw_minGasLimit: Minimum gas limit for the withdrawal message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST call
_initiateWithdrawalwith msg.sender as sender and provided_toas recipient - MUST emit WithdrawalInitiated and ETHBridgeInitiated or ERC20BridgeInitiated events
bridgeETH
Sends ETH to the sender's address on L1.
Parameters:
_minGasLimit: Minimum gas limit for the bridge message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST revert if caller is not an externally owned account
- MUST revert if msg.value does not equal the amount being bridged
- MUST send a cross-chain message to L1StandardBridge calling finalizeBridgeETH
- MUST emit WithdrawalInitiated and ETHBridgeInitiated events
bridgeETHTo
Sends ETH to a specified recipient's address on L1.
Parameters:
_to: Address to receive the ETH on L1_minGasLimit: Minimum gas limit for the bridge message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST revert if msg.value does not equal the amount being bridged
- MUST send a cross-chain message to L1StandardBridge calling finalizeBridgeETH
- MUST emit WithdrawalInitiated and ETHBridgeInitiated events
bridgeERC20
Sends ERC20 tokens to the sender's address on L1.
Parameters:
_localToken: Address of the ERC20 token on L2_remoteToken: Address of the corresponding token on L1_amount: Amount of tokens to bridge_minGasLimit: Minimum gas limit for the bridge message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST revert if caller is not an externally owned account
- MUST revert if msg.value is not zero
- MUST burn the tokens if _localToken is an OptimismMintableERC20
- MUST escrow the tokens if _localToken is a Native L2 Token
- MUST verify token pair matches for OptimismMintableERC20 tokens
- MUST send a cross-chain message to L1StandardBridge calling finalizeBridgeERC20
- MUST emit WithdrawalInitiated and ERC20BridgeInitiated events
bridgeERC20To
Sends ERC20 tokens to a specified recipient's address on L1.
Parameters:
_localToken: Address of the ERC20 token on L2_remoteToken: Address of the corresponding token on L1_to: Address to receive the tokens on L1_amount: Amount of tokens to bridge_minGasLimit: Minimum gas limit for the bridge message on L1_extraData: Optional data forwarded to L1 (not used for execution, only emitted)
Behavior:
- MUST revert if msg.value is not zero
- MUST burn the tokens if _localToken is an OptimismMintableERC20
- MUST escrow the tokens if _localToken is a Native L2 Token
- MUST verify token pair matches for OptimismMintableERC20 tokens
- MUST send a cross-chain message to L1StandardBridge calling finalizeBridgeERC20
- MUST emit WithdrawalInitiated and ERC20BridgeInitiated events
finalizeBridgeETH
Completes an ETH bridge from L1 and sends ETH to the recipient on L2.
Parameters:
_from: Address that initiated the bridge on L1_to: Address to receive the ETH on L2_amount: Amount of ETH being deposited_extraData: Optional data forwarded from L1 (not used for execution, only emitted)
Behavior:
- MUST revert if caller is not the L2CrossDomainMessenger
- MUST revert if xDomainMessageSender is not the L1StandardBridge
- MUST revert if the bridge is paused
- MUST revert if msg.value does not equal
_amount - MUST revert if
_tois the bridge contract itself - MUST revert if
_tois the messenger contract - MUST send
_amountof ETH to_to - MUST revert if the ETH transfer fails
- MUST emit DepositFinalized and ETHBridgeFinalized events
finalizeBridgeERC20
Completes an ERC20 bridge from L1 and mints or releases tokens to the recipient on L2.
Parameters:
_localToken: Address of the ERC20 token on L2_remoteToken: Address of the corresponding token on L1_from: Address that initiated the bridge on L1_to: Address to receive the tokens on L2_amount: Amount of tokens being deposited_extraData: Optional data forwarded from L1 (not used for execution, only emitted)
Behavior:
- MUST revert if caller is not the L2CrossDomainMessenger
- MUST revert if xDomainMessageSender is not the L1StandardBridge
- MUST revert if the bridge is paused
- MUST mint tokens to
_toif_localTokenis an OptimismMintableERC20 - MUST release escrowed tokens to
_toif_localTokenis a Native L2 Token - MUST verify token pair matches for OptimismMintableERC20 tokens
- MUST decrease the deposits mapping for Native L2 Tokens
- MUST emit DepositFinalized and ERC20BridgeFinalized events
l1TokenBridge
Returns the address of the L1StandardBridge contract.
Behavior:
- MUST return the address of the otherBridge
paused
Returns whether the bridge is paused.
Behavior:
- MUST always return false (L2 bridge cannot be paused)
MESSENGER
Legacy getter for the messenger contract.
Behavior:
- MUST return the L2CrossDomainMessenger contract address
OTHER_BRIDGE
Legacy getter for the other bridge contract.
Behavior:
- MUST return the L1StandardBridge contract address