Table of Contents
A number of teams across the Optimism Collective have been working together on the developments of a “fault proof” system for the OP Stack. Fault proof mechanisms allow parties to create and dispute claims about the result of some linear computation. In the case of the OP Stack, this fault proof is designed to allow users to permissionlessly create and dispute claims about the state of an L2 blockchain that can be used to send messages from the L2 to the L1 blockchain.
In practice, one of the most important use-cases for sending messages from L2 to L1 is user withdrawals of ETH and other ERC-20 tokens from an OP Stack chain’s bridge. The new systems and smart contracts introduced with the fault proof mechanism modify the process by which users prove and finalize withdrawal transactions. Given the critical nature of securing the tokens held within such a bridge, any changes to bridge smart contracts must be carefully scrutinized. Analyzing the security of these bridge changes is the primary focus of this engagement.
Let’s quickly run through the existing withdrawal process and understand how this process is changing with the introduction of fault proofs.
graph LR
subgraph "External Contracts"
ExternalERC20(External ERC20 Contracts)
ExternalERC721(External ERC721 Contracts)
end
subgraph "L1 Smart Contracts"
L1StandardBridge(L1StandardBridge)
L1ERC721Bridge(L1ERC721Bridge)
L1CrossDomainMessenger(L1CrossDomainMessenger)
L2OutputOracle(L2OutputOracle)
OptimismPortal(OptimismPortal)
SuperchainConfig(SuperchainConfig)
SystemConfig(SystemConfig)
end
subgraph "User Interactions"
Users(Users)
end
subgraph "System Interactions"
Proposer(PROPOSER)
Guardian(CHALLENGER)
end
click L1StandardBridge "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1StandardBridge.sol>" "L1StandardBridge.sol"
click L1ERC721Bridge "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol>" "L1ERC721Bridge.sol"
click L1CrossDomainMessenger "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol>" "L1CrossDomainMessenger.sol"
click L2OutputOracle "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol>" "L2OutputOracle.sol"
click OptimismPortal "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol>" "OptimismPortal.sol"
click SuperchainConfig "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/SuperchainConfig.sol>" "SuperchainConfig.sol"
click SystemConfig "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/SystemConfig.sol>" "SystemConfig.sol"
Proposer -->|propose state outputs| L2OutputOracle
Guardian -->|remove invalid state outputs| L2OutputOracle
ExternalERC20 <-->|mint/burn/transfer| L1StandardBridge
ExternalERC721 <-->|mint/burn/transfer| L1ERC721Bridge
L1StandardBridge <-->|send/receive message| L1CrossDomainMessenger
L1ERC721Bridge <-->|send/receive message| L1CrossDomainMessenger
L1CrossDomainMessenger <-->|package/send/receive message| OptimismPortal
L1StandardBridge -.->|query pause state| SuperchainConfig
L1ERC721Bridge -.->|query pause state| SuperchainConfig
L1CrossDomainMessenger -.->|query pause state| SuperchainConfig
OptimismPortal -.->|query pause state| SuperchainConfig
OptimismPortal -.->|query config| SystemConfig
OptimismPortal -.->|query proposed states| L2OutputOracle
Users <-->|deposit/withdraw ETH/ERC20| L1StandardBridge
Users <-->|deposit/withdraw ERC721| L1ERC721Bridge
Users -->|prove/execute withdrawal transactions| OptimismPortal
Users -->|replay messages| L1CrossDomainMessenger
classDef extContracts stroke:#ff9,stroke-width:2px;
classDef l1Contracts stroke:#bbf,stroke-width:2px;
classDef l1EOA stroke:#bbb,stroke-width:2px;
classDef userInt stroke:#f9a,stroke-width:2px;
classDef systemUser stroke:#f9a,stroke-width:2px;
classDef critical stroke:#0f0,stroke-width:2px;
class ExternalERC20,ExternalERC721 extContracts;
class L1StandardBridge,L1ERC721Bridge,L1CrossDomainMessenger,SuperchainConfig,SystemConfig l1Contracts;
class Users userInt;
class Batcher,Proposer,Guardian systemUser;
class OptimismPortal,L2OutputOracle critical;
<aside> 💡 An editable and zoomable version of the above diagram is available here.
</aside>
Above is a diagram that illustrates the relationships between various OP Stack bridge smart contracts before the introduction of fault proofs. Most of these smart contracts are not changing during this update. Contracts highlighted in GREEN are being modified. The OptimismPortal
contract located at the heart of the bridging system is on the receiving end of some of the largest necessary changes.
Before fault proofs, the OptimismPortal
contract retrieves claims about the state of the L2 from the L2OutputOracle
contract. Claims can only be published by the designated PROPOSER
role and invalid claims can be removed by the designated CHALLENGER
role. Users prove withdrawals to the OptimismPortal
against these claims and can finalize their withdrawals as long as their selected claim was not later removed. In a moment we’ll take a look at how this process changes after fault proofs.
graph LR
subgraph "External Contracts"
ExternalERC20(External ERC20 Contracts)
ExternalERC721(External ERC721 Contracts)
end
subgraph "L1 Smart Contracts"
L1StandardBridge(L1StandardBridge)
L1ERC721Bridge(L1ERC721Bridge)
L1CrossDomainMessenger(L1CrossDomainMessenger)
OptimismPortal(OptimismPortal)
SuperchainConfig(SuperchainConfig)
SystemConfig(SystemConfig)
DisputeGameFactory(DisputeGameFactory)
FaultDisputeGame(FaultDisputeGame)
DelayedWETH(DelayedWETH)
end
subgraph "User Interactions"
Users(Users)
end
subgraph "System Interactions"
Guardian(GUARDIAN)
end
click L1StandardBridge "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1StandardBridge.sol>" "L1StandardBridge.sol"
click L1ERC721Bridge "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol>" "L1ERC721Bridge.sol"
click L1CrossDomainMessenger "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol>" "L1CrossDomainMessenger.sol"
click L2OutputOracle "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol>" "L2OutputOracle.sol"
click OptimismPortal "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol>" "OptimismPortal.sol"
click SuperchainConfig "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/SuperchainConfig.sol>" "SuperchainConfig.sol"
click SystemConfig "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/L1/SystemConfig.sol>" "SystemConfig.sol"
click DisputeGameFactory "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol>" "DisputeGameFactory.sol"
click FaultDisputeGame "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol>" "FaultDisputeGame.sol"
click DelayedWETH "<https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock/src/dispute/weth/DelayedWETH.sol>" "DelayedWETH.sol"
ExternalERC20 <-->|mint/burn/transfer| L1StandardBridge
ExternalERC721 <-->|mint/burn/transfer| L1ERC721Bridge
L1StandardBridge <-->|send/receive message| L1CrossDomainMessenger
L1ERC721Bridge <-->|send/receive message| L1CrossDomainMessenger
L1CrossDomainMessenger <-->|package/send/receive message| OptimismPortal
L1StandardBridge -.->|query pause state| SuperchainConfig
L1ERC721Bridge -.->|query pause state| SuperchainConfig
L1CrossDomainMessenger -.->|query pause state| SuperchainConfig
OptimismPortal -.->|query pause state| SuperchainConfig
OptimismPortal -.->|query config| SystemConfig
OptimismPortal -.->|query game address| DisputeGameFactory
OptimismPortal -.->|query game state| FaultDisputeGame
DisputeGameFactory -->|creates instances of| FaultDisputeGame
FaultDisputeGame -->|store/retrieve bonds| DelayedWETH
Users <-->|deposit/withdraw ETH/ERC20| L1StandardBridge
Users <-->|deposit/withdraw ERC721| L1ERC721Bridge
Users -->|prove/execute withdrawal transactions| OptimismPortal
Users -->|create dispute games| DisputeGameFactory
Users -->|participate in dispute games| FaultDisputeGame
Users -->|replay messages| L1CrossDomainMessenger
Guardian -->|blacklist dispute games| OptimismPortal
Guardian -->|change respected game type| OptimismPortal
classDef extContracts stroke:#ff9,stroke-width:2px;
classDef l1Contracts stroke:#bbf,stroke-width:2px;
classDef l1EOA stroke:#bbb,stroke-width:2px;
classDef userInt stroke:#f9a,stroke-width:2px;
classDef systemUser stroke:#f9a,stroke-width:2px;
classDef critical stroke:#0f0,stroke-width:2px;
class ExternalERC20,ExternalERC721 extContracts;
class L1StandardBridge,L1ERC721Bridge,L1CrossDomainMessenger,SuperchainConfig,SystemConfig l1Contracts;
class Users userInt;
class Batcher,Proposer,Guardian systemUser;
class OptimismPortal,DisputeGameFactory,FaultDisputeGame,DelayedWETH critical;
<aside> 💡 An editable and zoomable version of this diagram is available here.
</aside>
Above is a diagram that illustrates the relationships between various OP Stack bridge smart contracts after the introduction of fault proofs. Contracts that have been modified are highlighted in GREEN.
Most notable in these changes is the removal of the L2OutputOracle
contract and the introduction of the DisputeGameFactory
in its place. Unlike the L2OutputOracle
, the DisputeGameFactory
does not place limitations on which addresses can create claims about the state of the L2. Any user can trigger the DisputeGameFactory
to create a new claim and a corresponding FaultDisputeGame
so that any other user may argue about the validity of that claim.
Instead of proving withdrawals against proposals in the L2OutputOracle
, users now prove withdrawals against claims that exist as FaultDisputeGame
contracts. FaultDisputeGame
instances resolve either for or against the claim after a certain amount of time. If a game resolves in favor of a claim, then that claim can be used to finalize withdrawals inside of the OptimismPortal
.
Additionally, the permissionless nature of the FaultDisputeGame
contract necessitates the existence of a bonding system that requires users to stake ETH against the claims that they make. Bonds make the FaultDisputeGame
contract “incentive compatible” such that participants should always be incentivized to “play the game” correctly. As bond sizes can become large relatively quickly, the DelayedWETH
contract is introduced to act as a bond escrow contract that delays bond withdrawals to allow for recovery in case of an emergency.