ZK Dispute Game Migration
Table of Contents
- Overview
- In-Flight Withdrawal Safety
- Common Mechanics
- Path A: SFDG → ZKDG (Isolated Chain)
- Path B: SPDG → ZKDG (Isolated Chain)
- Path C: Interop Set (Shared Contracts)
Overview
Migrations to ZKDisputeGame target chains that already run super-root dispute games. A migration registers
ZK_DISPUTE_GAME and makes it the respected game type.
| Path | Respected game type before migration | Context |
|---|---|---|
| A | SUPER_CANNON_KONA (SuperFaultDisputeGame, SFDG) | Isolated chain |
| B | SUPER_PERMISSIONED (SuperPermissionedDisputeGame, SPDG) | Isolated chain |
| C | A super-root game type | Interop set with shared contracts |
In-Flight Withdrawal Safety
MCP clones embed the implementation address at deployment time. Old SFDG/SPDG game clones created
before the migration retain their original implementation bytecode forever. New ZK_DISPUTE_GAME clones
created after setImplementation() in DisputeGameFactory use the ZKDG implementation.
wasRespectedGameTypeWhenCreated is snapshotted at game creation. AnchorStateRegistry.isGameClaimValid()
reads this flag during withdrawal finalization. Games created under the old respected type remain
valid for in-flight withdrawal finalization even after the migration.
rootClaimByChainId is declared on all game types in scope (SFDG, SPDG, ZKDG). The Portal
calls it on all games whose type is in the isSuperGame allowlist. Old games already return the
correct answer via their existing implementation. No special handling is needed for pre-migration
games during Portal withdrawal verification.
Source-type games created after the respected game type switches to ZK_DISPUTE_GAME are not respected
(wasRespectedGameTypeWhenCreated == false), so they cannot back withdrawals. Neither mechanism for switching the
respected game type changes retirementTimestamp: AnchorStateRegistry.initialize() only sets it when it is zero,
and setRespectedGameType() does not touch it. Games created before the switch therefore stay valid. Forming an
interop set with migrate() is different: it retires all pre-migration games; see
iMIG-014.
Common Mechanics
-
Use an OPCM release that carries the ZK contracts. The release provides
zkDisputeGameImplandsp1PlonkAdapterImpl(see OPCM Integration). -
Register
ZK_DISPUTE_GAMEwithOPCMv2.upgrade(). The upgrade input contains all sixdisputeGameConfigs. TheZK_DISPUTE_GAMEentry is enabled, has a non-zeroinitBond, and carriesabi.encode(ZKDisputeGameConfig)asgameArgs. OPCM registers the ZK game with the 3-argument overload and sets its init bond:disputeGameFactory.setImplementation( GameTypes.ZK_DISPUTE_GAME, zkDisputeGameImpl, makeGameArgs(...) // 140-byte packed CWIA args built from ZKDisputeGameConfig ); disputeGameFactory.setInitBond(GameTypes.ZK_DISPUTE_GAME, initBond);Old game clones are unaffected. New
ZK_DISPUTE_GAMEgames usezkDisputeGameImpl.The same upgrade MAY disable the source game type by setting its entry to
enabled = falsewith a zeroinitBond. This requires switching the respected game type in the same upgrade with mechanism 3.1, because OPCM requires the resulting respected game type to be enabled. Disabling clears the source type's implementation and init bond, so no new games of that type can be created. Existing clones keep their implementation and resolve as before. -
Switch the respected game type to
ZK_DISPUTE_GAMEwith one of:-
the same
upgrade()call, with the extra instruction keyoverrides.cfg.startingRespectedGameTypeand dataabi.encode(GameTypes.ZK_DISPUTE_GAME). OPCM re-initializes theAnchorStateRegistrywith it; or -
a later Guardian call:
anchorStateRegistry.setRespectedGameType(GameTypes.ZK_DISPUTE_GAME);This lets operators register
ZK_DISPUTE_GAMEfirst and switch once honest ZK actors are running.
Before the switch, an honest ZK proposer, prover and challenger (see Honest Actors) MUST be operational and funded. This is the chain operator's responsibility and is not enforced by OPCM.
-
-
Keep the anchor state.
upgrade()always re-initializes theAnchorStateRegistry, but it preserves the anchor root, the anchor game, the blacklist andretirementTimestamp. The starting anchor root cannot be overridden during an upgrade. SFDG and SPDG already commit to super roots, the samebytes32format thatZKDGuses, so the existing anchor is a valid starting point for the firstZKDGgame (parentIndex = type(uint32).max).
Migrating from a classic output-root FaultDisputeGame with upgrade() is not supported: its anchor is not a
super root and cannot be re-seeded during an upgrade.
Path A: SFDG → ZKDG (Isolated Chain)
Single chain with its own DisputeGameFactory, AnchorStateRegistry, and OptimismPortal.
Execute Common Mechanics.
Path B: SPDG → ZKDG (Isolated Chain)
Single chain currently using the permissioned dispute game, migrating to permissionless ZK proofs.
Execute Common Mechanics.
Path C: Interop Set (Shared Contracts)
This case covers chains sharing a single DisputeGameFactory, AnchorStateRegistry, DelayedWETH, and
ETHLockbox under the interop model.
OPContractsManagerMigrator.migrate()forms an interop set from independent chains. It deploys the sharedDisputeGameFactory,AnchorStateRegistryandETHLockbox, and reuses the first chain'sDelayedWETHas the shared one. It MAY registerZK_DISPUTE_GAMEon the new sharedDisputeGameFactory. TheZK_DISPUTE_GAMEconfig MUST have a non-zeroinitBond, otherwisemigrate()reverts withOPContractsManagerMigrator_InvalidInitBond, and a validZKDisputeGameConfig(see Configuration Validation), otherwisemigrate()reverts withOPContractsManagerMigrator_InvalidZKDisputeGameConfig.- The starting respected game type passed to
migrate()MUST be one thatmigrate()supports, otherwisemigrate()reverts withOPContractsManagerMigrator_InvalidStartingRespectedGameType. - A set that already shares contracts registers
ZK_DISPUTE_GAMEthroughOPCMv2.upgrade()on a member (Common Mechanics step 2).migrate()reverts withOPContractsManagerMigrator_ChainAlreadyMigratedfor a chain that is already in a set. ZK_DISPUTE_GAMEbecomes the respected game type either directly throughmigrate(), wheremigrate()supports it, or later through mechanism 3.1 on a member'supgrade()or mechanism 3.2 (see Common Mechanics).OPCMv2.upgrade()on any member upgrades the shared contracts for the whole set.