OPContractsManagerMigrator
Table of Contents
- Overview
- Definitions
- Assumptions
- aMIG-001: Member Chains already run this release
- aMIG-002: Every Member Chain already has an ETHLockbox
- aMIG-003: A single trusted ProxyAdmin owner governs the whole set
- aMIG-004: The Starting Anchor State is correct
- aMIG-005: The input describes the complete set
- aMIG-006: Retired dispute games resolve
- aMIG-007: Member Chains already run permissionless dispute games
- Invariants
- iMIG-001: Migration happens at most once per chain
- iMIG-002: ETH is conserved across migration
- iMIG-003: Member Chains have distinct, non-zero chain IDs
- iMIG-004: Migration is atomic and complete
- iMIG-005: A single Pause Identifier governs the set
- iMIG-006: Retired contracts remain coherent with the set
- iMIG-007: No legacy dispute game configuration survives
- iMIG-008: Shared Contracts depend only on set-scoped contracts
- iMIG-009: The set has one governance scope
- iMIG-010: Per-chain configuration is otherwise preserved
- iMIG-011: The Starting Anchor State is well formed
- iMIG-012: Registered dispute games are playable
- iMIG-013: Custom gas token chains are not migrated
- iMIG-014: Withdrawal proofs do not survive migration
- iMIG-015: Member Chains agree on the shared delays
Overview
OPContractsManagerMigrator is the OPCM component that merges a group of independent OP Stack chains into a single Interop Set. Migration happens once per chain and cannot be reversed.
It provides two capabilities:
- Interop Set Migration: deploying the Shared Contracts for a new Interop
Set, moving every Member Chain onto them, pooling every member's ETH into the
set's single
ETHLockbox, and registering the super-root dispute games that will defend the set. Like the system upgrade capability, it is designed to be invoked by delegatecall from the ProxyAdmin owner, as it holds no authority itself. - Migration Validation: proving, after the fact, that the resulting configuration is the one that was intended. This capability is provided by OPContractsManagerMigrationValidator and is specified alongside migration here, because it exists only to check migration's output and shares every definition with it.
Both components are stateless and neither is versioned independently of OPCM. They act entirely with the authority of the caller.
Relationship to the OPContractsManager specification
Interop Set Migration is subject to the invariants of the OPCM specification, with three deliberate exceptions. Each is a considered trade, not an oversight:
- It must not be available while a Member Chain is paused, in contrast to i01-011. Migration changes each member's Pause Identifier, so running it under an active pause would silently discard that pause. See iMIG-005.
- Its Shared Contract addresses are not deterministic, in contrast to i01-009. An Interop Set has no chain ID of its own, and the chain ID only ever serves as a salt input, so migration substitutes a value derived from the block it executes in. Two attempts at the same migration therefore produce different addresses, and operators cannot predict them.
- It accepts a variable-length list of super-root dispute game configurations, rather than one configuration per valid game type in a fixed order as system deployment and system upgrade require. An Interop Set is defended by super-root games only, so the fixed shape does not apply. Validation still expects both super-root game types, because a set must keep defending its members with the permissionless games they already run. See aMIG-007.
Definitions
Migration
The one-time operation that turns a group of independent chains into an Interop Set. It is one-way. Nothing in these contracts returns a member to standalone operation, so undoing a migration would require a contract upgrade.
Interop Set
The group of OP Stack chains that share one ETHLockbox, one DisputeGameFactory and one
AnchorStateRegistry, and whose state is proven together as a single
Super Root. Every member keeps its own SystemConfig and
OptimismPortal. The OptimismPortal Interop specification
calls this the op-governed dependency set. It is the L1 contract counterpart of the
dependency set, which is a consensus-layer concept. The two
are expected to describe the same group of chains. Nothing in these contracts enforces that.
Member Chain
A chain in an Interop Set. Membership is permanent: nothing in these contracts removes a chain from a set.
Shared Contracts
The contracts an Interop Set holds in common: its ETHLockbox, its
DisputeGameFactory, its AnchorStateRegistry and its DelayedWETH. Migration deploys the first
three and adopts the fourth one. The migration input is the list of SystemConfigs that defines the
set, and the set takes the existing DelayedWETH of the member at index 0, then points every
member's SystemConfig at it. Members are supplied in ascending chain ID order, so index 0 is
always the lowest-chain-ID member.
Retired Contracts
The per-chain DisputeGameFactory, ETHLockbox, AnchorStateRegistry and DelayedWETH that a
Member Chain used before migration. The index-0 member's DelayedWETH is the one
exception: the set adopts it rather than retiring it. Retired Contracts remain deployed and
reachable, because dispute games created before migration continue to resolve against them and
their bonds must remain claimable.
The following diagram shows a two-chain set after migration, with Chain A at index 0. The shared
DelayedWETH is Chain A's existing contract rather than a new deployment. The Retired Contracts
resolve pause through the set's shared ETHLockbox rather than through their own, which keeps a
game created before the migration subject to the same pause as the rest of the set:
flowchart LR
subgraph CA["Member Chain A"]
SCA[SystemConfig] -- holds address --> PA[OptimismPortal]
end
subgraph CB["Member Chain B"]
SCB[SystemConfig] -- holds address --> PB[OptimismPortal]
end
subgraph SH["Shared Contracts"]
LB[ETHLockbox]
ASR[AnchorStateRegistry]
DGF[DisputeGameFactory]
WETH["DelayedWETH<br/>(Chain A's, index 0)"]
end
subgraph RT["Retired Contracts"]
RA["A: old DGF / ASR / ETHLockbox"]
RB["B: old DGF / ASR / ETHLockbox / DelayedWETH"]
end
PA -- ETH custody --> LB
PA -- game validity --> ASR
PB -- ETH custody --> LB
PB -- game validity --> ASR
ASR -- game registration --> DGF
ASR -- pause, guardian --> LB
WETH -- pause --> LB
SCA -- holds address --> WETH
SCB -- holds address --> WETH
RA -. pause, guardian .-> LB
RB -. pause, guardian .-> LB
Pause Identifier
The address that a chain's pause state is keyed against in SuperchainConfig. Before joining an
Interop Set a chain is identified by its own ETHLockbox. Afterwards every member
is identified by the set's shared ETHLockbox, so one scoped pause covers the whole set. See the
Pause Identifier rules for the permitted values.
Starting Anchor State
The Super Root and sequence number that the set's shared
AnchorStateRegistry is initialized with, serving the same role as the
Starting Anchor State
of a single-chain registry. It is computed off-chain from the state of every Member Chain.
Cleared Game Types
The set of dispute game types that migration removes from the DisputeGameFactory of every
Retired Contracts entry. It is deliberately broader than the game types
an OPCM release considers valid, because a retired factory may still hold a game type that has
since been withdrawn from service.
Migration Validation
The set of checks performed after migration, comparing the on-chain result against the operator's stated migration intent. Validation reports every discrepancy or anomaly it finds rather than reverting at the first, so that a single dry run surfaces the complete list of problems.
Assumptions
aMIG-001: Member Chains already run this release
Every Member Chain already runs the Contract Release that the migrating OPCM represents.
System upgrades accept a chain one major version behind. Migration accepts only a chain already on this release, whether through this OPCM or through a replacement OPCM for the same release.
Mitigations
- The permitted-sequence check is applied to every chain in the input before any state is mutated
- Refusing the next-major case makes it not possible to reach a new release through the migration OPCM path
- Migration preserves each member's record of its last-used OPCM instead of marking the migration as an upgrade, so the chain's upgrade history stays accurate
aMIG-002: Every Member Chain already has an ETHLockbox
Every Member Chain has an ETHLockbox installed and its lockbox feature enabled
before migration begins.
This is a precondition of the release rather than something migration establishes. Migration reads each member's pause state, which is resolved through that member's lockbox, so a member without one cannot be read at all.
Mitigations
- The system upgrade capability installs and enables an
ETHLockboxfor every chain on this release, so any chain eligible under aMIG-001 satisfies this - A member without a lockbox causes migration to revert
aMIG-003: A single trusted ProxyAdmin owner governs the whole set
All Member Chains are administered by the same ProxyAdmin owner, which is trusted and operating within governance constraints, and migration executes with that owner's authority.
Members may have distinct ProxyAdmin contracts. Only the owner must be common, because it is the
owner rather than the contract that migration and every subsequent upgrade acts as.
Mitigations
- Migration only succeeds when
delegatecalled - The common owner is checked across every chain in the input before any state is mutated
aMIG-004: The Starting Anchor State is correct
The Starting Anchor State supplied to migration is a truthful Super Root of every Member Chain at the stated sequence number.
Migration cannot check a Super Root against L2 state on-chain. It rejects only roots which carry a zero anchor hash or sequence numbers that leave no room for a new one, so a wrong but plausible anchor is installed exactly as supplied.
Mitigations
- Migration rejects an empty anchor and one that leaves no room for a successor proposal, so the obvious placeholder values cannot be installed by accident
- Validation compares the installed anchor against the operator's stated intent
aMIG-005: The input describes the complete set
The chains supplied to migration are exactly the chains joining the set. All of them are joining, and none is already in a set.
Migration supports only the case of independent chains merging into one new set. Adding a chain to an existing set, splitting a set, or migrating part of a set is not supported.
Mitigations
- Any chain already in a set is refused, so an existing set cannot be migrated again or extended
- A mixed input containing one or more already-migrated chains is rejected
aMIG-006: Retired dispute games resolve
Dispute games created before migration resolve on their own against their Retired Contracts, and their bonds are reclaimed afterwards.
Migration does not resolve, cancel or settle games that are in progress.
Mitigations
- Retired factories keep the games they created, and migration removes only the ability to create new ones
- Retired registries and
DelayedWETHcontracts keep resolving pause and guardian through the set's sharedETHLockbox, so a retired game is neither stranded nor exempt from a pause - Bond withdrawals already pending in a retired
DelayedWETHsurvive migration
aMIG-007: Member Chains already run permissionless dispute games
Every Member Chain already runs permissionless dispute games, so the Interop Set it joins must go on defending it with permissionless super-root games.
Migration does not check this. It registers whatever list of super-root game configurations it is
given as its input, including a list holding the permissioned game type only. Validation checks one
fixed shape instead: the set's shared DisputeGameFactory must have both the permissioned and the
permissionless super-root game type of this release registered. The permissioned game type is the
set's fallback, as it is for a single chain. A set that comes out of migration with permissioned
games only is a downgrade.
Mitigations
- Validation fails on a shared
DisputeGameFactorythat has no permissionless super-root game type, so the downgrade is not silently accepted - Migration is a privileged one-off, so the operator is responsible for supplying a valid configuration.
Invariants
iMIG-001: Migration happens at most once per chain
A chain that is already a Member Chain of an Interop Set must never be migrated again, and an attempt that includes even one such chain must fail in its entirety.
Impact
Severity: Critical
Re-migrating a set is destructive to every chain in it. A second migration deploys a fresh
ETHLockbox and drains the set's existing one into it. It also clears the game implementations from
the set's shared DisputeGameFactory. The result is a set with no playable dispute games and no
withdrawable ETH, for every member at once.
iMIG-002: ETH is conserved across migration
Every ETH balance held by a Member Chain's OptimismPortal or by its retired
ETHLockbox must end up in the set's shared ETHLockbox. Afterwards each member's OptimismPortal
and each retired ETHLockbox must hold no ETH, and the shared ETHLockbox must hold the sum of
what they held before.
Impact
Severity: Critical
The portal no longer draws on a retired contract, so it no longer backs anything, and withdrawals against it can never be paid. ETH counted twice would let more be withdrawn from the set than was ever deposited into it.
iMIG-003: Member Chains have distinct, non-zero chain IDs
No two Member Chains may report the same L2 chain ID, and no member may report a chain ID of zero.
Impact
Severity: Critical
An Interop Set's proofs key each member's output root by its chain ID. Two members sharing an ID would let a single withdrawal be finalized through both members' portals, paying it twice out of the shared liquidity pool.
iMIG-004: Migration is atomic and complete
Migration either fully succeeds for every Member Chain or fully reverts with no state changes, within a single transaction that fits in an Ethereum block.
Impact
Severity: Critical
If violated, the set could be left partially migrated. Some portals would point at the shared
contracts while the rest still pointed at their own. Liquidity would sit partly in the shared
ETHLockbox and partly in the retired ones. No single proof would cover every member. A withdrawal
could then be blocked or paid twice, depending on which side of the split it was proven against.
iMIG-005: A single Pause Identifier governs the set
After migration, every Member Chain must resolve its pause state and its guardian
through the set's shared ETHLockbox, so that one scoped pause covers the whole set.
To reach that state safely, migration must refuse to run while any member is paused under its existing Pause Identifier, and must leave no pause active against any retired identity.
Impact
Severity: Critical
Changing a chain's Pause Identifier while a pause is active drops that pause: the guardian's intervention silently stops applying, and withdrawals resume in the middle of the incident that prompted it. In the other direction, a pause left active against a retired identity is a pause nobody can see and nobody can lift through the set's controls.
iMIG-006: Retired contracts remain coherent with the set
Each Member Chain's retired AnchorStateRegistry and retired DelayedWETH must
resolve pause, guardian and SuperchainConfig through the set's shared ETHLockbox, while keeping
their own anchor state and respected game type unchanged.
Impact
Severity: High
If violated, a member's retired AnchorStateRegistry and DelayedWETH would keep asking their old
lockbox whether the set is paused. Only the shared ETHLockbox answers that question for the set,
because a lockbox reports the pause keyed to its own address. The guardian could halt the set and
these two contracts would still read "not paused".
The games that read them were created before migration, and have no other route to the set's pause state. A game caught resolving incorrectly could not be stopped, and its bonds would be paid out of a set the guardian had already halted. A pause keyed to the retired lockbox would do the reverse, freezing those games while the rest of the set carried on.
Reinitializing their anchor state rather than preserving it would invalidate the same games.
Pause is the only one of the three references that can diverge today, because every lockbox in a set
holds the same SuperchainConfig and so reports the same guardian. The guardian and
SuperchainConfig clauses keep the invariant sound if that ever stops being true.
iMIG-007: No legacy dispute game configuration survives
No game type may be left with an implementation on any Retired Contracts
DisputeGameFactory. The Cleared Game Types must therefore cover every game
type a chain on this release could have registered, including those the release has since withdrawn
from service. The set's shared DisputeGameFactory must carry only super-root game types, and must
include both the permissioned and the permissionless super-root game type of this release. See
aMIG-007.
Migration and validation must agree on which game types a retired factory has to be cleared of. Neither may work from its own list.
Impact
Severity: High
A game type left registered on a retired factory lets anyone create a new game there, against a registry the portal no longer respects. Bonds staked there back a game that can never settle a withdrawal. A stale initialization bond is harmless once the implementation is cleared, because creation reverts on the missing implementation before the factory reads the bond. If the two sides disagree about the list, validation passes while a game type is still live, which is precisely the failure this invariant exists to catch.
iMIG-008: Shared Contracts depend only on set-scoped contracts
No Shared Contract may resolve its pause state, its guardian or its
SuperchainConfig through a contract belonging to a single Member Chain. Every
dependency that governs the set must itself be scoped to the whole set.
Two references to per-chain contracts survive migration by design and neither invalidates this invariant:
- The index-0 member's
ProxyAdminadministers the three proxies migration deploys, and remains the admin of theDelayedWETHthe set adopts. aMIG-003 makes this safe. Every member'sProxyAdminis controlled by the same owner. - The set's shared
ETHLockboxrecords every member'sOptimismPortalas an authorized portal, and every retiredETHLockboxas an authorized lockbox. Each portal needs its entry to draw on the shared pool, and each retired lockbox needs its entry to hand its balance over.
Impact
Severity: High
A Shared Contract pointing at one member's per-chain contract makes that member the governance root of the set: the whole set's pause state and guardian resolve through one member's configuration, with nothing keeping that member aligned afterwards. It also breaks upgrade idempotency, because upgrading any other member would aim the set's governance reference at itself instead, and makes it impossible to state a validation predicate that holds for more than one member at a time.
iMIG-009: The set has one governance scope
All Member Chains must share one ProxyAdmin owner and one SuperchainConfig, and
the set's shared DisputeGameFactory must be owned by that ProxyAdmin owner.
Impact
Severity: High
Members under different owners or different SuperchainConfig contracts cannot be paused, upgraded
or guarded as a unit, which is the premise the shared contracts are built on. A shared factory owned
by anyone else would let that party set the dispute game implementations for every member.
iMIG-010: Per-chain configuration is otherwise preserved
Migration must not change any Member Chain configuration beyond what joining the
set requires: adopting the set's Shared Contracts, enabling the features the
set depends on, and moving the portal onto the shared ETHLockbox and registry. Every other
configuration value must survive migration unchanged.
Impact
Severity: Critical
Migration touches every member's most privileged contracts. Silently changing an owner would transfer control of the chain. Silently changing a batcher hash or a gas limit would break it.
iMIG-011: The Starting Anchor State is well formed
The Starting Anchor State must not be empty and must leave room for a successor proposal. The set's starting respected game type must be a super-root game type, and must be one of the game types migration registers on the shared factory.
Impact
Severity: High
An empty or out-of-range anchor leaves the shared registry in a state no game can build on, halting proposals for every member. A respected game type with no implementation registered is unplayable, so no proposal can be made or defended and withdrawals stop for the whole set.
iMIG-012: Registered dispute games are playable
Every dispute game configuration migration installs must be one it can actually install and one that can be played: a super-root game type with a registered implementation, enabled, with an initialization bond consistent with whether that game type charges bonds, and with a non-zero absolute prestate where the game type requires one.
A configuration that passes validation must not then fail installation.
Impact
Severity: High
An unplayable game blocks proposals, and therefore withdrawals, for every member of the set. A game type that passes the configuration checks and then fails installation turns a caller mistake into a failure halfway through the operation, which is a far worse diagnostic than an upfront rejection.
iMIG-013: Custom gas token chains are not migrated
A Member Chain must not use a custom gas token. Migration must reject a chain whose
SystemConfig has the custom gas token feature enabled before any state is mutated.
Impact
Severity: Critical
A custom gas token chain's native asset is not ETH. Joining a set enables the interop feature on the
member, which activates the interop ETH predeploys on its L2. A
cross-chain ETH transfer burns the sending chain's native asset and mints ETH on the receiving
chain. That ETH is withdrawable from the set's single shared ETHLockbox, so every unit such a
member sends draws on ETH it never deposited.
iMIG-014: Withdrawal proofs do not survive migration
No withdrawal proven before migration may be finalized afterwards.
The set's shared AnchorStateRegistry is initialized during migration, so its
Retirement Timestamp
is the migration block. Every game created before that block is a
Retired Game to the set, and
a proof against a Retired Game can never be finalized. Those games are not registered with the set's
shared DisputeGameFactory either, which rejects them on that path as well. The withdrawal must be
proven again, against a game the shared factory created, and then wait a fresh proof maturity delay.
This does not contradict aMIG-006. Games in progress still resolve and still pay their bonds. A game keeps the registry it was created with, and that registry keeps its own retirement timestamp, so the game is not retired there. Only the portal moved.
Impact
Severity: Critical
A pre-migration game proves one chain's output root. A proof that stayed valid against such a game
would pay out of the set's pooled ETHLockbox, on the strength of a game nobody is defending,
drawing on ETH the other members deposited.
The user sees nothing at migration time. Their proof reverts only when they try to finalize it, so the operator has to tell them to prove again.
iMIG-015: Member Chains agree on the shared delays
The shared AnchorStateRegistry must be initialized with the Dispute Game Finality Delay that
every Member Chain's retired registry reports, and the shared DelayedWETH must
keep the Withdrawal Delay that every member's retired DelayedWETH reports. Migration must revert
if any two members differ on either value. Each portal keeps its own Proof Maturity Delay.
Impact
Severity: High
If violated, a member's games and bonds would be subject to a review period or lockup it did not configure, lengthening or shortening the Guardian's window without the governance step that a setter call requires.