From d0c6dc120dfd253c342ddd30afc5cb5970f3fee5 Mon Sep 17 00:00:00 2001 From: inphi Date: Tue, 14 Oct 2025 21:25:11 -0400 Subject: [PATCH 01/15] opcm: Update upgrade method for disputegame-v2 --- .../abi/OPContractsManagerUpgrader.json | 11 ++ .../snapshots/semver-lock.json | 6 +- .../src/L1/OPContractsManager.sol | 138 +++++++++++++++--- .../OPContractsManagerStandardValidator.sol | 131 +++++++++++++---- .../src/dispute/lib/LibGameArgs.sol | 41 ++++++ .../test/L1/OPContractsManager.t.sol | 52 +++++-- .../test/dispute/lib/LibGameArgs.t.sol | 131 +++++++++++++++++ 7 files changed, 445 insertions(+), 65 deletions(-) create mode 100644 packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol create mode 100644 packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json index a092f317994..2ddf0b230a2 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json @@ -366,6 +366,17 @@ "name": "IdentityPrecompileCallFailed", "type": "error" }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "devFeature", + "type": "bytes32" + } + ], + "name": "InvalidDevFeatureAccess", + "type": "error" + }, { "inputs": [], "name": "NotABlueprint", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index caa8ace5ae4..68792e7adfb 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,11 +21,11 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0x4025118658a1c56c4fc2d0166081e6d27da980318e749e7811c7178115e4413e", - "sourceCodeHash": "0xdb243ac7475b0214b8f662aa04f696d9ff213dade6b1bdade379e84df419b75a" + "sourceCodeHash": "0xe83044b4004521d60eb19aadb30dab45b9f0661e445fa1329e371c1d23fed123" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0x57d6a6729d887ead009d518e8f17fa0d26bfc97b8efe1494ab4ef8dbb000d109", - "sourceCodeHash": "0x1d58891954cf782d2fe4f112b0c7fd25be991c2b8873f10d8545c653b517cac9" + "initCodeHash": "0xd171ea5f458bf0bea6222299283b07c73f437e8b017913afe8587bbe220d8980", + "sourceCodeHash": "0x199e719889127fd743936ab78e5b9336ce17d2bd9cbcca013bfca7399e925dbe" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { "initCodeHash": "0x5bf576ea7f566e402a997204988471fc9b971410aa9dff8fe810b10baf6b7456", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index d87b903c86e..3c5662d29d1 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -25,6 +25,7 @@ import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; +import { IFaultDisputeGameV2 } from "interfaces/dispute/v2/IFaultDisputeGameV2.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol"; import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol"; @@ -869,32 +870,61 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { IPermissionedDisputeGame permissionedDisputeGame = IPermissionedDisputeGame(address(getGameImplementation(dgf, GameTypes.PERMISSIONED_CANNON))); - // Update the PermissionedDisputeGame. - // We're reusing the same DelayedWETH and ASR contracts. - deployAndSetNewGameImpl({ - _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionedDisputeGame)), - _newDelayedWeth: permissionedDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionedDisputeGame.anchorStateRegistry(), - _gameType: GameTypes.PERMISSIONED_CANNON, - _opChainConfig: _opChainConfig - }); - - // Now retrieve the permissionless game. - IFaultDisputeGame permissionlessDisputeGame = - IFaultDisputeGame(address(getGameImplementation(dgf, GameTypes.CANNON))); - - // If it exists, replace its implementation. - // We're reusing the same DelayedWETH and ASR contracts. - if (address(permissionlessDisputeGame) != address(0)) { + if (!isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + // Update the PermissionedDisputeGame. + // We're reusing the same DelayedWETH and ASR contracts. deployAndSetNewGameImpl({ _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionlessDisputeGame)), - _newDelayedWeth: permissionlessDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionlessDisputeGame.anchorStateRegistry(), - _gameType: GameTypes.CANNON, + _disputeGame: IDisputeGame(address(permissionedDisputeGame)), + _newDelayedWeth: permissionedDisputeGame.weth(), + _newAnchorStateRegistryProxy: permissionedDisputeGame.anchorStateRegistry(), + _gameType: GameTypes.PERMISSIONED_CANNON, _opChainConfig: _opChainConfig }); + + // Now retrieve the permissionless game. + IFaultDisputeGame permissionlessDisputeGame = + IFaultDisputeGame(address(getGameImplementation(dgf, GameTypes.CANNON))); + + // If it exists, replace its implementation. + // We're reusing the same DelayedWETH and ASR contracts. + if (address(permissionlessDisputeGame) != address(0)) { + deployAndSetNewGameImpl({ + _l2ChainId: _l2ChainId, + _disputeGame: IDisputeGame(address(permissionlessDisputeGame)), + _newDelayedWeth: permissionlessDisputeGame.weth(), + _newAnchorStateRegistryProxy: permissionlessDisputeGame.anchorStateRegistry(), + _gameType: GameTypes.CANNON, + _opChainConfig: _opChainConfig + }); + } + } else { + setNewGameImplV2({ + _impls: _impls, + _l2ChainId: _l2ChainId, + _disputeGame: IDisputeGame(address(permissionedDisputeGame)), + _newDelayedWeth: permissionedDisputeGame.weth(), + _newAnchorStateRegistryProxy: permissionedDisputeGame.anchorStateRegistry(), + _gameType: GameTypes.PERMISSIONED_CANNON, + _opChainConfig: _opChainConfig + }); + + IFaultDisputeGame permissionlessDisputeGame = + IFaultDisputeGame(address(getGameImplementation(dgf, GameTypes.CANNON))); + + // If it exists, replace its implementation. + // We're reusing the same DelayedWETH and ASR contracts. + if (address(permissionlessDisputeGame) != address(0)) { + setNewGameImplV2({ + _impls: _impls, + _l2ChainId: _l2ChainId, + _disputeGame: IDisputeGame(address(permissionlessDisputeGame)), + _newDelayedWeth: permissionlessDisputeGame.weth(), + _newAnchorStateRegistryProxy: permissionlessDisputeGame.anchorStateRegistry(), + _gameType: GameTypes.CANNON, + _opChainConfig: _opChainConfig + }); + } } } @@ -1007,6 +1037,70 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { // Set the new implementation. setDGFImplementation(dgf, _gameType, IDisputeGame(newGame)); } + + /// @notice Sets the latest dispute game v2 implementations + /// @param _impls The container for the new dispute game implementations. + /// @param _l2ChainId The L2 chain ID + /// @param _disputeGame The current dispute game implementation in the dispute game factory + /// @param _newDelayedWeth The new delayed WETH implementation + /// @param _newAnchorStateRegistryProxy The new anchor state registry proxy + /// @param _gameType The type of game to deploy + /// @param _opChainConfig The OP chain configuration + function setNewGameImplV2( + OPContractsManager.Implementations memory _impls, + uint256 _l2ChainId, + IDisputeGame _disputeGame, + IDelayedWETH _newDelayedWeth, + IAnchorStateRegistry _newAnchorStateRegistryProxy, + GameType _gameType, + OPContractsManager.OpChainConfig memory _opChainConfig + ) + internal + { + // If the prestate is set in the config, use it. If not set, we'll try to use the prestate + // that already exists on the current dispute game. + Claim absolutePrestate; + if (Claim.unwrap(_opChainConfig.absolutePrestate) == bytes32(0)) { + // SAFETY: both V1 and V2 games support absolutePrestate() + absolutePrestate = IFaultDisputeGameV2(address(_disputeGame)).absolutePrestate(); + } else { + absolutePrestate = _opChainConfig.absolutePrestate; + } + + // As a sanity check, if the prestate is zero here, revert. + if (absolutePrestate.raw() == bytes32(0)) { + revert OPContractsManager.PrestateNotSet(); + } + + IDisputeGame newGame; + bytes memory gameArgs; + if (GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON)) { + newGame = IDisputeGame(_impls.permissionedDisputeGameV2Impl); + address proposer = getProposer(IPermissionedDisputeGame(address(_disputeGame))); + address challenger = getChallenger(IPermissionedDisputeGame(address(_disputeGame))); + gameArgs = abi.encodePacked( + absolutePrestate, // 32 bytes + _impls.mipsImpl, // 20 bytes + address(_newAnchorStateRegistryProxy), // 20 bytes + address(_newDelayedWeth), // 20 bytes + _l2ChainId, // 32 bytes + proposer, // 20 bytes + challenger // 20 bytes + ); + } else { + newGame = IDisputeGame(_impls.faultDisputeGameV2Impl); + gameArgs = abi.encodePacked( + absolutePrestate, // 32 bytes + _impls.mipsImpl, // 20 bytes + address(_newAnchorStateRegistryProxy), // 20 bytes + address(_newDelayedWeth), // 20 bytes + _l2ChainId // 32 bytes + ); + } + + IDisputeGameFactory dgf = IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); + setDGFImplementation(dgf, _gameType, IDisputeGame(newGame), gameArgs); + } } contract OPContractsManagerDeployer is OPContractsManagerBase { diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol index f82b21b248c..2ba31683152 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol @@ -10,6 +10,7 @@ import { Constants } from "src/libraries/Constants.sol"; import { Hash } from "src/dispute/lib/Types.sol"; import { Features } from "src/libraries/Features.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; // Interfaces import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; @@ -30,6 +31,7 @@ import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol"; import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol"; import { ISemver } from "interfaces/universal/ISemver.sol"; import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol"; +import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; /// @title OPContractsManagerStandardValidator /// @notice This contract is used to validate the configuration of the L1 contracts of an OP Stack chain. @@ -38,8 +40,8 @@ import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol"; /// before and after an upgrade. contract OPContractsManagerStandardValidator is ISemver { /// @notice The semantic version of the OPContractsManagerStandardValidator contract. - /// @custom:semver 1.18.0 - string public constant version = "1.18.0"; + /// @custom:semver 1.19.0 + string public constant version = "1.19.0"; /// @notice The SuperchainConfig contract. ISuperchainConfig public superchainConfig; @@ -124,6 +126,25 @@ contract OPContractsManagerStandardValidator is ISemver { address challenger; } + /// @notice Struct containing the unified game args for a dispute game implementation. + struct DisputeGameImplementation { + address gameAddress; + uint256 maxGameDepth; + uint256 splitDepth; + Duration maxClockDuration; + Duration clockExtension; + GameType gameType; + // extra args + uint256 l2SequenceNumber; + // dispute-game v2 game args + Claim absolutePrestate; + IBigStepper vm; + IAnchorStateRegistry asr; + IDelayedWETH weth; + uint256 l2ChainId; + address challenger; + } + /// @notice Constructor for the OPContractsManagerStandardValidator contract. constructor( Implementations memory _implementations, @@ -495,10 +516,12 @@ contract OPContractsManagerStandardValidator is ISemver { return _errors; } + DisputeGameImplementation memory _gameImpl = + _decodeDisputeGameImpl(_game, _factory.gameArgs(GameTypes.PERMISSIONED_CANNON), true); _errors = assertValidDisputeGame( _errors, _sysCfg, - _game, + _gameImpl, _factory, _absolutePrestate, _l2ChainID, @@ -510,7 +533,7 @@ contract OPContractsManagerStandardValidator is ISemver { // Challenger is specific to the PermissionedDisputeGame contract. address _challenger = expectedChallenger(_overrides); - _errors = internalRequire(_game.challenger() == _challenger, "PDDG-130", _errors); + _errors = internalRequire(_gameImpl.challenger == _challenger, "PDDG-130", _errors); return _errors; } @@ -538,10 +561,12 @@ contract OPContractsManagerStandardValidator is ISemver { return _errors; } + DisputeGameImplementation memory _gameImpl = + _decodeDisputeGameImpl(_game, _factory.gameArgs(GameTypes.CANNON), false); _errors = assertValidDisputeGame( _errors, _sysCfg, - _game, + _gameImpl, _factory, _absolutePrestate, _l2ChainID, @@ -558,7 +583,7 @@ contract OPContractsManagerStandardValidator is ISemver { function assertValidDisputeGame( string memory _errors, ISystemConfig _sysCfg, - IPermissionedDisputeGame _game, + DisputeGameImplementation memory _game, IDisputeGameFactory _factory, bytes32 _absolutePrestate, uint256 _l2ChainID, @@ -571,41 +596,44 @@ contract OPContractsManagerStandardValidator is ISemver { view returns (string memory) { - IAnchorStateRegistry _asr = _game.anchorStateRegistry(); - (Hash anchorRoot,) = _asr.getAnchorRoot(); + (Hash anchorRoot,) = _game.asr.getAnchorRoot(); + + if (!DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + _errors = internalRequire( + LibString.eq(getVersion(_game.gameAddress), permissionedDisputeGameVersion()), + string.concat(_errorPrefix, "-20"), + _errors + ); + } else { + // TODO: enable once the feature is in production + } _errors = internalRequire( - LibString.eq(getVersion(address(_game)), permissionedDisputeGameVersion()), - string.concat(_errorPrefix, "-20"), - _errors - ); - _errors = internalRequire( - GameType.unwrap(_game.gameType()) == GameType.unwrap(_gameType), string.concat(_errorPrefix, "-30"), _errors - ); - _errors = internalRequire( - Claim.unwrap(_game.absolutePrestate()) == _absolutePrestate, string.concat(_errorPrefix, "-40"), _errors + GameType.unwrap(_game.gameType) == GameType.unwrap(_gameType), string.concat(_errorPrefix, "-30"), _errors ); - _errors = internalRequire(_game.l2ChainId() == _l2ChainID, string.concat(_errorPrefix, "-60"), _errors); - _errors = internalRequire(_game.l2SequenceNumber() == 0, string.concat(_errorPrefix, "-70"), _errors); _errors = internalRequire( - Duration.unwrap(_game.clockExtension()) == 10800, string.concat(_errorPrefix, "-80"), _errors + Claim.unwrap(_game.absolutePrestate) == _absolutePrestate, string.concat(_errorPrefix, "-40"), _errors ); - _errors = internalRequire(_game.splitDepth() == 30, string.concat(_errorPrefix, "-90"), _errors); - _errors = internalRequire(_game.maxGameDepth() == 73, string.concat(_errorPrefix, "-100"), _errors); + _errors = internalRequire(_game.l2ChainId == _l2ChainID, string.concat(_errorPrefix, "-60"), _errors); + _errors = internalRequire(_game.l2SequenceNumber == 0, string.concat(_errorPrefix, "-70"), _errors); + _errors = + internalRequire(Duration.unwrap(_game.clockExtension) == 10800, string.concat(_errorPrefix, "-80"), _errors); + _errors = internalRequire(_game.splitDepth == 30, string.concat(_errorPrefix, "-90"), _errors); + _errors = internalRequire(_game.maxGameDepth == 73, string.concat(_errorPrefix, "-100"), _errors); _errors = internalRequire( - Duration.unwrap(_game.maxClockDuration()) == 302400, string.concat(_errorPrefix, "-110"), _errors + Duration.unwrap(_game.maxClockDuration) == 302400, string.concat(_errorPrefix, "-110"), _errors ); _errors = internalRequire(Hash.unwrap(anchorRoot) != bytes32(0), string.concat(_errorPrefix, "-120"), _errors); - _errors = assertValidDelayedWETH(_errors, _sysCfg, _game.weth(), _admin, _overrides, _errorPrefix); - _errors = assertValidAnchorStateRegistry(_errors, _sysCfg, _factory, _asr, _admin, _errorPrefix); + _errors = assertValidDelayedWETH(_errors, _sysCfg, _game.weth, _admin, _overrides, _errorPrefix); + _errors = assertValidAnchorStateRegistry(_errors, _sysCfg, _factory, _game.asr, _admin, _errorPrefix); - _errors = assertValidMipsVm(_errors, IMIPS64(address(_game.vm())), _errorPrefix); + _errors = assertValidMipsVm(_errors, IMIPS64(address(_game.vm)), _errorPrefix); // Only assert valid preimage oracle if the game VM is valid, since otherwise // the contract is likely to revert. - if (address(_game.vm()) == mipsImpl) { - _errors = assertValidPreimageOracle(_errors, _game.vm().oracle(), _errorPrefix); + if (address(_game.vm) == mipsImpl) { + _errors = assertValidPreimageOracle(_errors, _game.vm.oracle(), _errorPrefix); } return _errors; @@ -798,4 +826,51 @@ contract OPContractsManagerStandardValidator is ISemver { return finalErrors; } + + /// @notice Internal function to read all information from a dispute game while supporting both v1 and v2 dispute + /// games. + function _decodeDisputeGameImpl( + IPermissionedDisputeGame _game, + bytes memory _gameArgsBytes, + bool _isPermissioned + ) + internal + view + returns (DisputeGameImplementation memory gameImpl_) + { + bytes32 absolutePrestate; + address vm; + address asr; + address weth; + uint256 l2ChainId; + address challengerAddress; + if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + (absolutePrestate, vm, asr, weth, l2ChainId,, challengerAddress) = LibGameArgs.decode(_gameArgsBytes); + } else { + absolutePrestate = Claim.unwrap(_game.absolutePrestate()); + vm = address(_game.vm()); + asr = address(_game.anchorStateRegistry()); + weth = address(_game.weth()); + l2ChainId = _game.l2ChainId(); + if (_isPermissioned) { + challengerAddress = _game.challenger(); + } + } + + gameImpl_ = DisputeGameImplementation({ + gameAddress: address(_game), + maxGameDepth: _game.maxGameDepth(), + splitDepth: _game.splitDepth(), + maxClockDuration: _game.maxClockDuration(), + clockExtension: _game.clockExtension(), + gameType: _game.gameType(), + l2SequenceNumber: _game.l2SequenceNumber(), + absolutePrestate: Claim.wrap(absolutePrestate), + vm: IBigStepper(vm), + asr: IAnchorStateRegistry(asr), + weth: IDelayedWETH(payable(weth)), + l2ChainId: l2ChainId, + challenger: challengerAddress + }); + } } diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol new file mode 100644 index 00000000000..ebb927f0115 --- /dev/null +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +/// @title LibGameArgs +/// @notice Library for decoding the game arguments used in dispute games. +library LibGameArgs { + /// @notice Decodes the game arguments from a bytes array. + /// @param _gameArgs The bytes array containing the encoded game arguments. + function decode(bytes memory _gameArgs) + internal + pure + returns ( + bytes32 absolutePrestate_, + address vm_, + address asr_, + address weth_, + uint256 l2ChainId_, + address proposer_, + address challenger_ + ) + { + uint256 len = _gameArgs.length; + require(len == 164 || len == 124, "GameArgs: decode with invalid length"); + assembly { + let d := add(_gameArgs, 32) + absolutePrestate_ := mload(d) + vm_ := shr(96, mload(add(d, 32))) + asr_ := shr(96, mload(add(d, 52))) + weth_ := shr(96, mload(add(d, 72))) + l2ChainId_ := mload(add(d, 92)) + } + + if (len == 164) { + assembly { + let d := add(_gameArgs, 32) + proposer_ := shr(96, mload(add(d, 124))) + challenger_ := shr(96, mload(add(d, 144))) + } + } + } +} diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index bd0951c487e..0becfff1f3e 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -21,6 +21,7 @@ import { Types } from "scripts/libraries/Types.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { GameType, Duration, Hash, Claim } from "src/dispute/lib/LibUDT.sol"; import { Proposal, GameTypes } from "src/dispute/lib/Types.sol"; +import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Interfaces @@ -246,11 +247,18 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { } // Create validationOverrides + address challengerOverride; + if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + (,,,,,, challengerOverride) = LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.PERMISSIONED_CANNON)); + } else { + challengerOverride = IPermissionedDisputeGame( + address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) + ).challenger(); + } IOPContractsManagerStandardValidator.ValidationOverrides memory validationOverrides = IOPContractsManagerStandardValidator.ValidationOverrides({ l1PAOMultisig: opChainConfigs[0].proxyAdmin.owner(), - challenger: IPermissionedDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON))) - .challenger() + challenger: challengerOverride }); // Grab the validator before we do the error assertion because otherwise the assertion will @@ -1243,6 +1251,12 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { runPastUpgrades(upgrader); } + function getDisputeGameV2AbsolutePrestate(GameType _gameType) internal view returns (Claim) { + bytes memory gameArgs = disputeGameFactory.gameArgs(_gameType); + (bytes32 absolutePrestate,,,,,,) = LibGameArgs.decode(gameArgs); + return Claim.wrap(absolutePrestate); + } + function test_upgradeOPChainOnly_succeeds() public { // Run the upgrade test and checks runCurrentUpgrade(upgrader); @@ -1297,11 +1311,18 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { runCurrentUpgrade(upgrader); // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = IPermissionedDisputeGame( - address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) - ).absolutePrestate(); - Claim fdgPrestateAfter = - IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))).absolutePrestate(); + Claim pdgPrestateAfter; + Claim fdgPrestateAfter; + if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); + fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); + } else { + pdgPrestateAfter = IPermissionedDisputeGame( + address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) + ).absolutePrestate(); + fdgPrestateAfter = + IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))).absolutePrestate(); + } // Assert that the absolute prestate is the non-zero value we set. assertEq(pdgPrestateAfter.raw(), bytes32(uint256(1))); @@ -1329,11 +1350,18 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { runCurrentUpgrade(upgrader); // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = IPermissionedDisputeGame( - address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) - ).absolutePrestate(); - Claim fdgPrestateAfter = - IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))).absolutePrestate(); + Claim pdgPrestateAfter; + Claim fdgPrestateAfter; + if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); + fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); + } else { + pdgPrestateAfter = IPermissionedDisputeGame( + address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) + ).absolutePrestate(); + fdgPrestateAfter = + IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))).absolutePrestate(); + } // Assert that the absolute prestate is the same as before the upgrade. assertEq(pdgPrestateAfter.raw(), pdgPrestateBefore.raw()); diff --git a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol new file mode 100644 index 00000000000..35ddf0f5b17 --- /dev/null +++ b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +import { Test } from "forge-std/Test.sol"; +import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; + +contract LibGameArgs_Harness { + function decode(bytes memory _buf) + public + pure + returns (bytes32, address, address, address, uint256, address, address) + { + return LibGameArgs.decode(_buf); + } +} + +/// @title LibGameArgs_Decode_Test +/// @notice Test contract for the LibGameArgs library's decode function. +contract LibGameArgs_Decode_Test is Test { + LibGameArgs_Harness internal harness; + + function setUp() public { + harness = new LibGameArgs_Harness(); + } + + /// @notice Struct to hold game arguments for testing purposes. + /// Avoids "stack too deep" errors in the test functions. + struct GameArgs { + bytes32 absolutePrestate; + address vm; + address asr; + address weth; + uint256 l2ChainId; + address proposer; + address challenger; + } + + function test_decodeFull_succeeds() public { + GameArgs memory args = GameArgs({ + absolutePrestate: keccak256(abi.encodePacked("absolutePrestate")), + vm: vm.randomAddress(), + asr: address(0x2), + weth: address(0x3), + l2ChainId: 42, + proposer: address(0x123), + challenger: address(0x456) + }); + bytes memory buf = abi.encodePacked( + args.absolutePrestate, args.vm, args.asr, args.weth, args.l2ChainId, args.proposer, args.challenger + ); + + ( + bytes32 _absolutePrestate, + address _vm, + address _asr, + address _weth, + uint256 _l2ChainId, + address _proposer, + address _challenger + ) = harness.decode(buf); + assertEq(_absolutePrestate, args.absolutePrestate); + assertEq(_vm, args.vm); + assertEq(_asr, args.asr); + assertEq(_weth, args.weth); + assertEq(_l2ChainId, args.l2ChainId); + assertEq(_proposer, args.proposer); + assertEq(_challenger, args.challenger); + } + + function test_decodeShort_succeeds() public { + GameArgs memory args = GameArgs({ + absolutePrestate: keccak256(abi.encodePacked("absolutePrestate")), + vm: vm.randomAddress(), + asr: address(0x2), + weth: address(0x3), + l2ChainId: 42, + proposer: address(0x123), + challenger: address(0x456) + }); + bytes memory buf = abi.encodePacked(args.absolutePrestate, args.vm, args.asr, args.weth, args.l2ChainId); + + ( + bytes32 _absolutePrestate, + address _vm, + address _asr, + address _weth, + uint256 _l2ChainId, + address _proposer, + address _challenger + ) = harness.decode(buf); + assertEq(_absolutePrestate, args.absolutePrestate); + assertEq(_vm, args.vm); + assertEq(_asr, args.asr); + assertEq(_weth, args.weth); + assertEq(_l2ChainId, args.l2ChainId); + assertEq(_proposer, address(0)); + assertEq(_challenger, address(0)); + } + + function test_decode_invalidLengthOverfull_reverts() public { + GameArgs memory args = GameArgs({ + absolutePrestate: keccak256(abi.encodePacked("absolutePrestate")), + vm: vm.randomAddress(), + asr: address(0x2), + weth: address(0x3), + l2ChainId: 42, + proposer: address(0x123), + challenger: address(0x456) + }); + bytes memory buf = abi.encodePacked( + args.absolutePrestate, + args.vm, + args.asr, + args.weth, + args.l2ChainId, + args.proposer, + args.challenger, + uint256(999) + ); + + vm.expectRevert("GameArgs: decode with invalid length"); + harness.decode(buf); + } + + function test_decode_invalidLength_reverts(bytes memory _buf) public { + bool ok = (_buf.length == 124 || _buf.length == 164); + vm.assume(!ok); + vm.expectRevert("GameArgs: decode with invalid length"); + harness.decode(_buf); + } +} From 55a98a3f94e801ae042a78c3212e05abd1a6b9f6 Mon Sep 17 00:00:00 2001 From: inphi Date: Wed, 15 Oct 2025 14:51:45 -0400 Subject: [PATCH 02/15] update opcm semver --- packages/contracts-bedrock/snapshots/semver-lock.json | 4 ++-- packages/contracts-bedrock/src/L1/OPContractsManager.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 68792e7adfb..af755b8cd26 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -20,8 +20,8 @@ "sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b" }, "src/L1/OPContractsManager.sol:OPContractsManager": { - "initCodeHash": "0x4025118658a1c56c4fc2d0166081e6d27da980318e749e7811c7178115e4413e", - "sourceCodeHash": "0xe83044b4004521d60eb19aadb30dab45b9f0661e445fa1329e371c1d23fed123" + "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", + "sourceCodeHash": "0xcb40feb5d14737e625db5b2d5819a67d33b08561e6561ce3614b60cc2abfc628" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0xd171ea5f458bf0bea6222299283b07c73f437e8b017913afe8587bbe220d8980", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 3c5662d29d1..b8d972a2965 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -1992,9 +1992,9 @@ contract OPContractsManager is ISemver { // -------- Constants and Variables -------- - /// @custom:semver 4.2.0 + /// @custom:semver 4.3.0 function version() public pure virtual returns (string memory) { - return "4.2.0"; + return "4.3.0"; } OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder; From 30df97d28d9c7421c1ee2afea9943589e5c36428 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 12:33:09 -0400 Subject: [PATCH 03/15] check game args; run post-upgrade checks --- .../OPContractsManagerStandardValidator.sol | 94 ++++++++++++------- .../src/dispute/lib/LibGameArgs.sol | 66 +++++++++---- .../test/L1/OPContractsManager.t.sol | 66 ++++++++++++- .../test/dispute/lib/LibGameArgs.t.sol | 68 ++++++-------- 4 files changed, 198 insertions(+), 96 deletions(-) diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol index 2ba31683152..3db11d1b7db 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol @@ -208,8 +208,12 @@ contract OPContractsManagerStandardValidator is ISemver { } /// @notice Returns the expected PermissionedDisputeGame version. - function permissionedDisputeGameVersion() public pure returns (string memory) { - return "1.8.0"; + function permissionedDisputeGameVersion() public view returns (string memory) { + if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + return "2.1.0"; + } else { + return "1.8.0"; + } } /// @notice Returns the expected PreimageOracle version. @@ -516,8 +520,9 @@ contract OPContractsManagerStandardValidator is ISemver { return _errors; } - DisputeGameImplementation memory _gameImpl = - _decodeDisputeGameImpl(_game, _factory.gameArgs(GameTypes.PERMISSIONED_CANNON), true); + bytes memory _gameArgs = _factory.gameArgs(GameTypes.PERMISSIONED_CANNON); + _errors = assertGameArgsLength(_errors, _gameArgs, true, "PDDG-15"); + DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, true); _errors = assertValidDisputeGame( _errors, _sysCfg, @@ -561,8 +566,9 @@ contract OPContractsManagerStandardValidator is ISemver { return _errors; } - DisputeGameImplementation memory _gameImpl = - _decodeDisputeGameImpl(_game, _factory.gameArgs(GameTypes.CANNON), false); + bytes memory _gameArgs = _factory.gameArgs(GameTypes.CANNON); + _errors = assertGameArgsLength(_errors, _gameArgs, false, "PDDG-15"); + DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, false); _errors = assertValidDisputeGame( _errors, _sysCfg, @@ -598,15 +604,11 @@ contract OPContractsManagerStandardValidator is ISemver { { (Hash anchorRoot,) = _game.asr.getAnchorRoot(); - if (!DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { - _errors = internalRequire( - LibString.eq(getVersion(_game.gameAddress), permissionedDisputeGameVersion()), - string.concat(_errorPrefix, "-20"), - _errors - ); - } else { - // TODO: enable once the feature is in production - } + _errors = internalRequire( + LibString.eq(getVersion(_game.gameAddress), permissionedDisputeGameVersion()), + string.concat(_errorPrefix, "-20"), + _errors + ); _errors = internalRequire( GameType.unwrap(_game.gameType) == GameType.unwrap(_gameType), string.concat(_errorPrefix, "-30"), _errors @@ -827,7 +829,34 @@ contract OPContractsManagerStandardValidator is ISemver { return finalErrors; } - /// @notice Internal function to read all information from a dispute game while supporting both v1 and v2 dispute + function assertGameArgsLength( + string memory _errors, + bytes memory _gameArgsBytes, + bool _isPermissioned, + string memory _errorPrefix + ) + internal + view + returns (string memory) + { + _errorPrefix = string.concat(_errorPrefix, "-GARGS"); + if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + if (_isPermissioned) { + _errors = internalRequire( + LibGameArgs.isValidPermissionedArgs(_gameArgsBytes), string.concat(_errorPrefix, "-10"), _errors + ); + } else { + _errors = internalRequire( + LibGameArgs.isValidPermissionlessArgs(_gameArgsBytes), string.concat(_errorPrefix, "-10"), _errors + ); + } + } else { + _errors = internalRequire(_gameArgsBytes.length == 0, string.concat(_errorPrefix, "-10"), _errors); + } + return _errors; + } + + // @notice Internal function to read all information from a dispute game while supporting both v1 and v2 dispute /// games. function _decodeDisputeGameImpl( IPermissionedDisputeGame _game, @@ -838,22 +867,17 @@ contract OPContractsManagerStandardValidator is ISemver { view returns (DisputeGameImplementation memory gameImpl_) { - bytes32 absolutePrestate; - address vm; - address asr; - address weth; - uint256 l2ChainId; - address challengerAddress; + LibGameArgs.GameArgs memory gameArgs; if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { - (absolutePrestate, vm, asr, weth, l2ChainId,, challengerAddress) = LibGameArgs.decode(_gameArgsBytes); + gameArgs = LibGameArgs.decode(_gameArgsBytes); } else { - absolutePrestate = Claim.unwrap(_game.absolutePrestate()); - vm = address(_game.vm()); - asr = address(_game.anchorStateRegistry()); - weth = address(_game.weth()); - l2ChainId = _game.l2ChainId(); + gameArgs.absolutePrestate = Claim.unwrap(_game.absolutePrestate()); + gameArgs.vm = address(_game.vm()); + gameArgs.anchorStateRegistry = address(_game.anchorStateRegistry()); + gameArgs.weth = address(_game.weth()); + gameArgs.l2ChainId = _game.l2ChainId(); if (_isPermissioned) { - challengerAddress = _game.challenger(); + gameArgs.challenger = _game.challenger(); } } @@ -865,12 +889,12 @@ contract OPContractsManagerStandardValidator is ISemver { clockExtension: _game.clockExtension(), gameType: _game.gameType(), l2SequenceNumber: _game.l2SequenceNumber(), - absolutePrestate: Claim.wrap(absolutePrestate), - vm: IBigStepper(vm), - asr: IAnchorStateRegistry(asr), - weth: IDelayedWETH(payable(weth)), - l2ChainId: l2ChainId, - challenger: challengerAddress + absolutePrestate: Claim.wrap(gameArgs.absolutePrestate), + vm: IBigStepper(gameArgs.vm), + asr: IAnchorStateRegistry(gameArgs.anchorStateRegistry), + weth: IDelayedWETH(payable(gameArgs.weth)), + l2ChainId: gameArgs.l2ChainId, + challenger: gameArgs.challenger }); } } diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol index ebb927f0115..cd185f49a33 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -4,38 +4,64 @@ pragma solidity ^0.8.15; /// @title LibGameArgs /// @notice Library for decoding the game arguments used in dispute games. library LibGameArgs { + /// @notice Struct representing the game arguments. + struct GameArgs { + bytes32 absolutePrestate; + address vm; + address anchorStateRegistry; + address weth; + uint256 l2ChainId; + address proposer; + address challenger; + } + /// @notice Decodes the game arguments from a bytes array. /// @param _gameArgs The bytes array containing the encoded game arguments. - function decode(bytes memory _gameArgs) - internal - pure - returns ( - bytes32 absolutePrestate_, - address vm_, - address asr_, - address weth_, - uint256 l2ChainId_, - address proposer_, - address challenger_ - ) - { + function decode(bytes memory _gameArgs) internal pure returns (GameArgs memory) { uint256 len = _gameArgs.length; require(len == 164 || len == 124, "GameArgs: decode with invalid length"); + + bytes32 absolutePrestate; + address vm; + address asr; + address weth; + uint256 l2ChainId; + address proposer; + address challenger; + assembly { let d := add(_gameArgs, 32) - absolutePrestate_ := mload(d) - vm_ := shr(96, mload(add(d, 32))) - asr_ := shr(96, mload(add(d, 52))) - weth_ := shr(96, mload(add(d, 72))) - l2ChainId_ := mload(add(d, 92)) + absolutePrestate := mload(d) + vm := shr(96, mload(add(d, 32))) + asr := shr(96, mload(add(d, 52))) + weth := shr(96, mload(add(d, 72))) + l2ChainId := mload(add(d, 92)) } if (len == 164) { assembly { + // skip length prefix let d := add(_gameArgs, 32) - proposer_ := shr(96, mload(add(d, 124))) - challenger_ := shr(96, mload(add(d, 144))) + proposer := shr(96, mload(add(d, 124))) + challenger := shr(96, mload(add(d, 144))) } } + return GameArgs({ + absolutePrestate: absolutePrestate, + vm: vm, + anchorStateRegistry: asr, + weth: weth, + l2ChainId: l2ChainId, + proposer: proposer, + challenger: challenger + }); + } + + function isValidPermissionlessArgs(bytes memory _args) internal pure returns (bool) { + return _args.length == 124; + } + + function isValidPermissionedArgs(bytes memory _args) internal pure returns (bool) { + return _args.length == 164; } } diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 0becfff1f3e..be0234666fa 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -249,7 +249,9 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { // Create validationOverrides address challengerOverride; if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { - (,,,,,, challengerOverride) = LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.PERMISSIONED_CANNON)); + LibGameArgs.GameArgs memory gameArgs = + LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.PERMISSIONED_CANNON)); + challengerOverride = gameArgs.challenger; } else { challengerOverride = IPermissionedDisputeGame( address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) @@ -288,6 +290,62 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { false, validationOverrides ); + + _runPostUpgradeSmokeTests(_opcm, opChainConfigs[0], challengerOverride); + } + + function permissionedGameProposer() internal view returns (address) { + if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + LibGameArgs.GameArgs memory gameArgs = + LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.PERMISSIONED_CANNON)); + return gameArgs.proposer; + } else { + return IPermissionedDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON))) + .proposer(); + } + } + + /// @notice Runs some smoke tests after an upgrade + function _runPostUpgradeSmokeTests( + IOPContractsManager _opcm, + IOPContractsManager.OpChainConfig memory _opChainConfig, + address _challenger + ) + internal + { + address expectedProposer = permissionedGameProposer(); + bytes32 expectedAbsolutePrestate = _opChainConfig.absolutePrestate.raw(); + address expectedVm = address(_opcm.implementations().mipsImpl); + + Claim claim = Claim.wrap(bytes32(uint256(1))); + uint256 bondAmount = disputeGameFactory.initBonds(GameTypes.PERMISSIONED_CANNON); + vm.deal(address(_challenger), bondAmount); + (, uint256 rootBlockNumber) = optimismPortal2.anchorStateRegistry().getAnchorRoot(); + uint256 l2BlockNumber = rootBlockNumber + 1; + + // Deploy a live game and ensure it's configured correctly. + vm.prank(expectedProposer, expectedProposer); + IPermissionedDisputeGame game = IPermissionedDisputeGame( + address( + disputeGameFactory.create{ value: bondAmount }( + GameTypes.PERMISSIONED_CANNON, claim, abi.encode(l2BlockNumber) + ) + ) + ); + // for now skip prestate check if it's not set since we don't know the pre-upgrade state + if (expectedAbsolutePrestate != bytes32(0)) { + vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); + } + vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); + vm.assertEq(l2ChainId, game.l2ChainId()); + vm.assertEq(302400, game.maxClockDuration().raw()); + vm.assertEq(10800, game.clockExtension().raw()); + vm.assertEq(73, game.maxGameDepth()); + vm.assertEq(30, game.splitDepth()); + vm.assertEq(l2BlockNumber, game.l2BlockNumber()); + vm.assertEq(_challenger, game.challenger()); + vm.assertEq(expectedProposer, game.proposer()); + vm.assertEq(expectedVm, address(game.vm())); } /// @notice Executes all past upgrades that have not yet been executed on mainnet as of the @@ -1252,9 +1310,9 @@ contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { } function getDisputeGameV2AbsolutePrestate(GameType _gameType) internal view returns (Claim) { - bytes memory gameArgs = disputeGameFactory.gameArgs(_gameType); - (bytes32 absolutePrestate,,,,,,) = LibGameArgs.decode(gameArgs); - return Claim.wrap(absolutePrestate); + bytes memory gameArgsBytes = disputeGameFactory.gameArgs(_gameType); + LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(gameArgsBytes); + return Claim.wrap(gameArgs.absolutePrestate); } function test_upgradeOPChainOnly_succeeds() public { diff --git a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol index 35ddf0f5b17..9e58e4a8da9 100644 --- a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol +++ b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol @@ -5,11 +5,7 @@ import { Test } from "forge-std/Test.sol"; import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; contract LibGameArgs_Harness { - function decode(bytes memory _buf) - public - pure - returns (bytes32, address, address, address, uint256, address, address) - { + function decode(bytes memory _buf) public pure returns (LibGameArgs.GameArgs memory) { return LibGameArgs.decode(_buf); } } @@ -49,22 +45,14 @@ contract LibGameArgs_Decode_Test is Test { args.absolutePrestate, args.vm, args.asr, args.weth, args.l2ChainId, args.proposer, args.challenger ); - ( - bytes32 _absolutePrestate, - address _vm, - address _asr, - address _weth, - uint256 _l2ChainId, - address _proposer, - address _challenger - ) = harness.decode(buf); - assertEq(_absolutePrestate, args.absolutePrestate); - assertEq(_vm, args.vm); - assertEq(_asr, args.asr); - assertEq(_weth, args.weth); - assertEq(_l2ChainId, args.l2ChainId); - assertEq(_proposer, args.proposer); - assertEq(_challenger, args.challenger); + LibGameArgs.GameArgs memory decoded = harness.decode(buf); + assertEq(decoded.absolutePrestate, args.absolutePrestate); + assertEq(decoded.vm, args.vm); + assertEq(decoded.anchorStateRegistry, args.asr); + assertEq(decoded.weth, args.weth); + assertEq(decoded.l2ChainId, args.l2ChainId); + assertEq(decoded.proposer, args.proposer); + assertEq(decoded.challenger, args.challenger); } function test_decodeShort_succeeds() public { @@ -79,22 +67,14 @@ contract LibGameArgs_Decode_Test is Test { }); bytes memory buf = abi.encodePacked(args.absolutePrestate, args.vm, args.asr, args.weth, args.l2ChainId); - ( - bytes32 _absolutePrestate, - address _vm, - address _asr, - address _weth, - uint256 _l2ChainId, - address _proposer, - address _challenger - ) = harness.decode(buf); - assertEq(_absolutePrestate, args.absolutePrestate); - assertEq(_vm, args.vm); - assertEq(_asr, args.asr); - assertEq(_weth, args.weth); - assertEq(_l2ChainId, args.l2ChainId); - assertEq(_proposer, address(0)); - assertEq(_challenger, address(0)); + LibGameArgs.GameArgs memory decoded = harness.decode(buf); + assertEq(decoded.absolutePrestate, args.absolutePrestate); + assertEq(decoded.vm, args.vm); + assertEq(decoded.anchorStateRegistry, args.asr); + assertEq(decoded.weth, args.weth); + assertEq(decoded.l2ChainId, args.l2ChainId); + assertEq(decoded.proposer, address(0)); + assertEq(decoded.challenger, address(0)); } function test_decode_invalidLengthOverfull_reverts() public { @@ -128,4 +108,18 @@ contract LibGameArgs_Decode_Test is Test { vm.expectRevert("GameArgs: decode with invalid length"); harness.decode(_buf); } + + function test_isValidPermissionlessArgs_works() public pure { + bytes memory validBuf = new bytes(124); + assertTrue(LibGameArgs.isValidPermissionlessArgs(validBuf)); + validBuf = new bytes(164); + assertFalse(LibGameArgs.isValidPermissionlessArgs(validBuf)); + } + + function test_isValidPermissionedArgs_works() public pure { + bytes memory validBuf = new bytes(164); + assertTrue(LibGameArgs.isValidPermissionedArgs(validBuf)); + validBuf = new bytes(124); + assertFalse(LibGameArgs.isValidPermissionedArgs(validBuf)); + } } From 0488e9b7ffe4552b78cdfef69eeddfcb1c60f926 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 12:36:40 -0400 Subject: [PATCH 04/15] update std validator semver lock --- .../snapshots/abi/OPContractsManagerStandardValidator.json | 2 +- packages/contracts-bedrock/snapshots/semver-lock.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json index 7ec9ab0bc71..f26d0c4eac5 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json @@ -289,7 +289,7 @@ "type": "string" } ], - "stateMutability": "pure", + "stateMutability": "view", "type": "function" }, { diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index af755b8cd26..397db80538d 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,8 +24,8 @@ "sourceCodeHash": "0xcb40feb5d14737e625db5b2d5819a67d33b08561e6561ce3614b60cc2abfc628" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0xd171ea5f458bf0bea6222299283b07c73f437e8b017913afe8587bbe220d8980", - "sourceCodeHash": "0x199e719889127fd743936ab78e5b9336ce17d2bd9cbcca013bfca7399e925dbe" + "initCodeHash": "0xdfe525d297e2e66ab1a70cd73266328f909b037e2ca6774a9a745addaad3980b", + "sourceCodeHash": "0x9050184d57210e450bfb1e7878c73c33277c876512d80a9b1e31f146b3ea1e07" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { "initCodeHash": "0x5bf576ea7f566e402a997204988471fc9b971410aa9dff8fe810b10baf6b7456", From 860717a25d1d1028b3938f9f7af48b9237b296d0 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 12:42:52 -0400 Subject: [PATCH 05/15] fix assertGameArgsLength error prefix --- packages/contracts-bedrock/snapshots/semver-lock.json | 4 ++-- .../src/L1/OPContractsManagerStandardValidator.sol | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 397db80538d..2ec7ac24f51 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,8 +24,8 @@ "sourceCodeHash": "0xcb40feb5d14737e625db5b2d5819a67d33b08561e6561ce3614b60cc2abfc628" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0xdfe525d297e2e66ab1a70cd73266328f909b037e2ca6774a9a745addaad3980b", - "sourceCodeHash": "0x9050184d57210e450bfb1e7878c73c33277c876512d80a9b1e31f146b3ea1e07" + "initCodeHash": "0x16ae8712b395d6397d0a5032175a415fc4438ce86dd3c3c714f253a16cb776b3", + "sourceCodeHash": "0xefae7f4e724d93332126c2d02522246b62d6122358140369fbc5597076a588e6" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { "initCodeHash": "0x5bf576ea7f566e402a997204988471fc9b971410aa9dff8fe810b10baf6b7456", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol index 3db11d1b7db..d7a6a3e6025 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol @@ -521,7 +521,7 @@ contract OPContractsManagerStandardValidator is ISemver { } bytes memory _gameArgs = _factory.gameArgs(GameTypes.PERMISSIONED_CANNON); - _errors = assertGameArgsLength(_errors, _gameArgs, true, "PDDG-15"); + _errors = assertGameArgsLength(_errors, _gameArgs, true, "PDDG"); DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, true); _errors = assertValidDisputeGame( _errors, @@ -567,7 +567,7 @@ contract OPContractsManagerStandardValidator is ISemver { } bytes memory _gameArgs = _factory.gameArgs(GameTypes.CANNON); - _errors = assertGameArgsLength(_errors, _gameArgs, false, "PDDG-15"); + _errors = assertGameArgsLength(_errors, _gameArgs, false, "PLDG"); DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, false); _errors = assertValidDisputeGame( _errors, From 02492ec6cee74565599523e269b31a68dc2fcba0 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 16:40:57 -0400 Subject: [PATCH 06/15] opcm and validator fixes --- .../snapshots/semver-lock.json | 6 ++-- .../src/L1/OPContractsManager.sol | 30 ++++++++++++++-- .../OPContractsManagerStandardValidator.sol | 35 +++++++++++++------ .../src/dispute/lib/LibGameArgs.sol | 1 + .../test/L1/OPContractsManager.t.sol | 33 ++++++++++++++--- .../test/dispute/lib/LibGameArgs.t.sol | 2 +- 6 files changed, 85 insertions(+), 22 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 2ec7ac24f51..a4e629a3d27 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,11 +21,11 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0xcb40feb5d14737e625db5b2d5819a67d33b08561e6561ce3614b60cc2abfc628" + "sourceCodeHash": "0xb7042fbe052a38abddd795cf0cf7f9499a7d5890b4234256384e3e9d8048d24f" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0x16ae8712b395d6397d0a5032175a415fc4438ce86dd3c3c714f253a16cb776b3", - "sourceCodeHash": "0xefae7f4e724d93332126c2d02522246b62d6122358140369fbc5597076a588e6" + "initCodeHash": "0xaaf8598284fbb84e60bb3d7772f85230cd88e2cd6be5aa5846d0e30525a0b799", + "sourceCodeHash": "0x30d7e4243a3bab7fea8504be2cd24f2c5ab3335b802d62282a374a458a08feec" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { "initCodeHash": "0x5bf576ea7f566e402a997204988471fc9b971410aa9dff8fe810b10baf6b7456", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index b8d972a2965..90903631f9b 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -13,6 +13,7 @@ import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { SemverComp } from "src/libraries/SemverComp.sol"; import { Features } from "src/libraries/Features.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; @@ -25,7 +26,6 @@ import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; -import { IFaultDisputeGameV2 } from "interfaces/dispute/v2/IFaultDisputeGameV2.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol"; import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol"; @@ -1061,8 +1061,11 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { // that already exists on the current dispute game. Claim absolutePrestate; if (Claim.unwrap(_opChainConfig.absolutePrestate) == bytes32(0)) { - // SAFETY: both V1 and V2 games support absolutePrestate() - absolutePrestate = IFaultDisputeGameV2(address(_disputeGame)).absolutePrestate(); + absolutePrestate = getAbsolutePrestate( + IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()), + address(_disputeGame), + _gameType + ); } else { absolutePrestate = _opChainConfig.absolutePrestate; } @@ -1101,6 +1104,27 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { IDisputeGameFactory dgf = IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); setDGFImplementation(dgf, _gameType, IDisputeGame(newGame), gameArgs); } + + // @notice Retrieves the absolute prestate for a dispute game, handling both V1 and V2 games. + function getAbsolutePrestate( + IDisputeGameFactory _dgf, + address _disputeGame, + GameType _gameType + ) + internal + view + returns (Claim) + { + bytes memory gameArgsBytes = _dgf.gameArgs(_gameType); + if (gameArgsBytes.length == 0) { + // assume we're dealing with v1 fdgs + return IFaultDisputeGame(_disputeGame).absolutePrestate(); + } else { + // v2 dispute game + LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(gameArgsBytes); + return Claim.wrap(gameArgs.absolutePrestate); + } + } } contract OPContractsManagerDeployer is OPContractsManagerBase { diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol index d7a6a3e6025..6acf9f6a1da 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol @@ -521,7 +521,13 @@ contract OPContractsManagerStandardValidator is ISemver { } bytes memory _gameArgs = _factory.gameArgs(GameTypes.PERMISSIONED_CANNON); - _errors = assertGameArgsLength(_errors, _gameArgs, true, "PDDG"); + bool lenCheckFailed; + (_errors, lenCheckFailed) = assertGameArgsLength(_errors, _gameArgs, true, "PDDG"); + if (lenCheckFailed) { + // bail out immediately to avoid trying to validate an invalid dispute game + return _errors; + } + DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, true); _errors = assertValidDisputeGame( _errors, @@ -567,7 +573,13 @@ contract OPContractsManagerStandardValidator is ISemver { } bytes memory _gameArgs = _factory.gameArgs(GameTypes.CANNON); - _errors = assertGameArgsLength(_errors, _gameArgs, false, "PLDG"); + bool lenCheckFailed; + (_errors, lenCheckFailed) = assertGameArgsLength(_errors, _gameArgs, false, "PLDG"); + if (lenCheckFailed) { + // bail out immediately to avoid trying to validate an invalid dispute game + return _errors; + } + DisputeGameImplementation memory _gameImpl = _decodeDisputeGameImpl(_game, _gameArgs, false); _errors = assertValidDisputeGame( _errors, @@ -837,23 +849,24 @@ contract OPContractsManagerStandardValidator is ISemver { ) internal view - returns (string memory) + returns (string memory errors_, bool failed_) { _errorPrefix = string.concat(_errorPrefix, "-GARGS"); if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { if (_isPermissioned) { - _errors = internalRequire( - LibGameArgs.isValidPermissionedArgs(_gameArgsBytes), string.concat(_errorPrefix, "-10"), _errors - ); + bool ok = LibGameArgs.isValidPermissionedArgs(_gameArgsBytes); + _errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors); + return (_errors, !ok); } else { - _errors = internalRequire( - LibGameArgs.isValidPermissionlessArgs(_gameArgsBytes), string.concat(_errorPrefix, "-10"), _errors - ); + bool ok = LibGameArgs.isValidPermissionlessArgs(_gameArgsBytes); + _errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors); + return (_errors, !ok); } } else { - _errors = internalRequire(_gameArgsBytes.length == 0, string.concat(_errorPrefix, "-10"), _errors); + bool ok = _gameArgsBytes.length == 0; + _errors = internalRequire(ok, string.concat(_errorPrefix, "-10"), _errors); + return (_errors, !ok); } - return _errors; } // @notice Internal function to read all information from a dispute game while supporting both v1 and v2 dispute diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol index cd185f49a33..70f2ff4350f 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -30,6 +30,7 @@ library LibGameArgs { address challenger; assembly { + // skip length prefix let d := add(_gameArgs, 32) absolutePrestate := mload(d) vm := shr(96, mload(add(d, 32))) diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index be0234666fa..029adab2a7f 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -109,11 +109,19 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { /// @notice Thrown when testing with an unsupported chain ID. error UnsupportedChainId(); + struct PreUpgradeState { + Claim cannonAbsolutePrestate; + Claim permissionedAbsolutePrestate; + IDelayedWETH cannonWethProxy; + IDelayedWETH permissionedCannonWethProxy; + } + uint256 l2ChainId; address upgrader; IOPContractsManager.OpChainConfig[] opChainConfigs; Claim absolutePrestate; string public opChain = Config.forkOpChain(); + PreUpgradeState preUpgradeState; function setUp() public virtual override { super.disableUpgradedFork(); @@ -152,6 +160,17 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { permissionedDisputeGame = IPermissionedDisputeGame(address(artifacts.mustGetAddress("PermissionedDisputeGame"))); faultDisputeGame = IFaultDisputeGame(address(artifacts.mustGetAddress("FaultDisputeGame"))); + // grab the pre-upgrade state + preUpgradeState = PreUpgradeState({ + cannonAbsolutePrestate: IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))) + .absolutePrestate(), + permissionedAbsolutePrestate: IPermissionedDisputeGame( + address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) + ).absolutePrestate(), + cannonWethProxy: delayedWeth, + permissionedCannonWethProxy: delayedWETHPermissionedGameProxy + }); + // Since this superchainConfig is already at the expected reinitializer version... // We do this to pass the reinitializer check when trying to upgrade the superchainConfig contract. @@ -315,6 +334,9 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { { address expectedProposer = permissionedGameProposer(); bytes32 expectedAbsolutePrestate = _opChainConfig.absolutePrestate.raw(); + if (expectedAbsolutePrestate == bytes32(0)) { + expectedAbsolutePrestate = preUpgradeState.permissionedAbsolutePrestate.raw(); + } address expectedVm = address(_opcm.implementations().mipsImpl); Claim claim = Claim.wrap(bytes32(uint256(1))); @@ -332,10 +354,9 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { ) ) ); - // for now skip prestate check if it's not set since we don't know the pre-upgrade state - if (expectedAbsolutePrestate != bytes32(0)) { - vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); - } + (,,,, Claim rootClaim,,) = game.claimData(0); + + vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); vm.assertEq(l2ChainId, game.l2ChainId()); vm.assertEq(302400, game.maxClockDuration().raw()); @@ -346,6 +367,10 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { vm.assertEq(_challenger, game.challenger()); vm.assertEq(expectedProposer, game.proposer()); vm.assertEq(expectedVm, address(game.vm())); + vm.assertEq(address(preUpgradeState.permissionedCannonWethProxy), address(game.weth())); + vm.assertEq(expectedProposer, game.gameCreator()); + vm.assertEq(claim.raw(), rootClaim.raw()); + vm.assertEq(blockhash(block.number - 1), game.l1Head().raw()); } /// @notice Executes all past upgrades that have not yet been executed on mainnet as of the diff --git a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol index 9e58e4a8da9..b1aafeb397e 100644 --- a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol +++ b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol @@ -102,7 +102,7 @@ contract LibGameArgs_Decode_Test is Test { harness.decode(buf); } - function test_decode_invalidLength_reverts(bytes memory _buf) public { + function testFuzz_decode_invalidLength_reverts(bytes memory _buf) public { bool ok = (_buf.length == 124 || _buf.length == 164); vm.assume(!ok); vm.expectRevert("GameArgs: decode with invalid length"); From 6d65ec4686002fef499cdb4f4c8921d412b98b9d Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 18:01:19 -0400 Subject: [PATCH 07/15] lint LibGameArgs --- .../snapshots/abi/OPContractsManagerStandardValidator.json | 5 +++++ .../snapshots/abi/OPContractsManagerUpgrader.json | 5 +++++ packages/contracts-bedrock/snapshots/semver-lock.json | 2 +- packages/contracts-bedrock/src/dispute/lib/Errors.sol | 7 +++++++ packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol | 6 +++++- .../contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol | 5 +++-- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json index f26d0c4eac5..b09166a2529 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json @@ -465,5 +465,10 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [], + "name": "InvalidGameArgsLength", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json index 2ddf0b230a2..df01bf97b0e 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json @@ -377,6 +377,11 @@ "name": "InvalidDevFeatureAccess", "type": "error" }, + { + "inputs": [], + "name": "InvalidGameArgsLength", + "type": "error" + }, { "inputs": [], "name": "NotABlueprint", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index a4e629a3d27..2d322bf2512 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,7 +24,7 @@ "sourceCodeHash": "0xb7042fbe052a38abddd795cf0cf7f9499a7d5890b4234256384e3e9d8048d24f" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0xaaf8598284fbb84e60bb3d7772f85230cd88e2cd6be5aa5846d0e30525a0b799", + "initCodeHash": "0x94f761c9648b31ab4d8dff3278df45a17e1fa02cc146ae46db4944bc61f5d2af", "sourceCodeHash": "0x30d7e4243a3bab7fea8504be2cd24f2c5ab3335b802d62282a374a458a08feec" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { diff --git a/packages/contracts-bedrock/src/dispute/lib/Errors.sol b/packages/contracts-bedrock/src/dispute/lib/Errors.sol index 43e77177745..a11e5aa1be8 100644 --- a/packages/contracts-bedrock/src/dispute/lib/Errors.sol +++ b/packages/contracts-bedrock/src/dispute/lib/Errors.sol @@ -142,3 +142,10 @@ error BadAuth(); /// @notice Thrown when trying to close a game while the system is paused. error GamePaused(); + +//////////////////////////////////////////////////////////////// +// `LibGameArgs` Errors // +//////////////////////////////////////////////////////////////// + +/// @notice Thrown when the length of the game arguments is invalid. +error InvalidGameArgsLength(); diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol index 70f2ff4350f..508f5706492 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; +import { InvalidGameArgsLength } from "src/dispute/lib/Errors.sol"; + /// @title LibGameArgs /// @notice Library for decoding the game arguments used in dispute games. library LibGameArgs { @@ -19,7 +21,9 @@ library LibGameArgs { /// @param _gameArgs The bytes array containing the encoded game arguments. function decode(bytes memory _gameArgs) internal pure returns (GameArgs memory) { uint256 len = _gameArgs.length; - require(len == 164 || len == 124, "GameArgs: decode with invalid length"); + if (len != 164 && len != 124) { + revert InvalidGameArgsLength(); + } bytes32 absolutePrestate; address vm; diff --git a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol index b1aafeb397e..0f6ee1e429b 100644 --- a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol +++ b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.15; import { Test } from "forge-std/Test.sol"; import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; +import { InvalidGameArgsLength } from "src/dispute/lib/Errors.sol"; contract LibGameArgs_Harness { function decode(bytes memory _buf) public pure returns (LibGameArgs.GameArgs memory) { @@ -98,14 +99,14 @@ contract LibGameArgs_Decode_Test is Test { uint256(999) ); - vm.expectRevert("GameArgs: decode with invalid length"); + vm.expectRevert(InvalidGameArgsLength.selector); harness.decode(buf); } function testFuzz_decode_invalidLength_reverts(bytes memory _buf) public { bool ok = (_buf.length == 124 || _buf.length == 164); vm.assume(!ok); - vm.expectRevert("GameArgs: decode with invalid length"); + vm.expectRevert(InvalidGameArgsLength.selector); harness.decode(_buf); } From 1fa0605faf0afbee1e2d11afebc69ac868e43d15 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 18:18:17 -0400 Subject: [PATCH 08/15] fix interfaces; natspec --- .../interfaces/L1/IOPContractsManagerStandardValidator.sol | 2 ++ packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol index 15cb768e44d..56aa6dace01 100644 --- a/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol @@ -34,6 +34,8 @@ interface IOPContractsManagerStandardValidator { address challenger; } + error InvalidGameArgsLength(); + function version() external view returns (string memory); function anchorStateRegistryImpl() external view returns (address); function challenger() external view returns (address); diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol index 508f5706492..32395d40c11 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -62,10 +62,12 @@ library LibGameArgs { }); } + /// @notice Checks if the provided game arguments are valid for a permissionless game. function isValidPermissionlessArgs(bytes memory _args) internal pure returns (bool) { return _args.length == 124; } + /// @notice Checks if the provided game arguments are valid for a permissioned game. function isValidPermissionedArgs(bytes memory _args) internal pure returns (bool) { return _args.length == 164; } From 0d4f9fe5412c291e70e196e9f2efb3874fa16ba8 Mon Sep 17 00:00:00 2001 From: inphi Date: Thu, 16 Oct 2025 18:20:17 -0400 Subject: [PATCH 09/15] fix natspec in opcm --- packages/contracts-bedrock/snapshots/semver-lock.json | 2 +- packages/contracts-bedrock/src/L1/OPContractsManager.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 2d322bf2512..28eebfd29ee 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,7 +21,7 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0xb7042fbe052a38abddd795cf0cf7f9499a7d5890b4234256384e3e9d8048d24f" + "sourceCodeHash": "0x8d6120049f482b88688ca8480ab92b12190524a5453b1a24afbe2ff4397c7c88" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x94f761c9648b31ab4d8dff3278df45a17e1fa02cc146ae46db4944bc61f5d2af", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 90903631f9b..a952d18d4c7 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -1105,7 +1105,7 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { setDGFImplementation(dgf, _gameType, IDisputeGame(newGame), gameArgs); } - // @notice Retrieves the absolute prestate for a dispute game, handling both V1 and V2 games. + /// @notice Retrieves the absolute prestate for a dispute game, handling both V1 and V2 games. function getAbsolutePrestate( IDisputeGameFactory _dgf, address _disputeGame, From d4ae9af9be82731670532bc60614df8737543415 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 17 Oct 2025 12:04:23 -0400 Subject: [PATCH 10/15] forwards-compatible challenger/proposer retrieval --- .../snapshots/semver-lock.json | 2 +- .../src/L1/OPContractsManager.sol | 69 ++++++++++++++----- .../test/L1/OPContractsManager.t.sol | 1 + 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 28eebfd29ee..a4eadbc8761 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,7 +21,7 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0x8d6120049f482b88688ca8480ab92b12190524a5453b1a24afbe2ff4397c7c88" + "sourceCodeHash": "0x53926724bed6040c04befbf072fa42c0ce025f395bd3aeb9efe7f95afea00e1c" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x94f761c9648b31ab4d8dff3278df45a17e1fa02cc146ae46db4944bc61f5d2af", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index a952d18d4c7..70f633eeb7c 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -297,16 +297,52 @@ abstract contract OPContractsManagerBase { return _disputeGame.l2ChainId(); } - /// @notice Retrieves the proposer address for a given game - function getProposer(IPermissionedDisputeGame _disputeGame) internal view returns (address) { + /// @notice Retrieves the proposer address for a given v1 game + function getProposerV1(IPermissionedDisputeGame _disputeGame) internal view returns (address) { return _disputeGame.proposer(); } - /// @notice Retrieves the challenger address for a given game - function getChallenger(IPermissionedDisputeGame _disputeGame) internal view returns (address) { + /// @notice Retrieves the proposer address for a given v1 or v2 game + function getProposer( + IDisputeGameFactory _disputeGameFactory, + IPermissionedDisputeGame _disputeGame, + GameType _gameType + ) + internal + view + returns (address) + { + bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); + if (gameArgsBytes.length == 0) { + return _disputeGame.proposer(); + } else { + return LibGameArgs.decode(gameArgsBytes).proposer; + } + } + + /// @notice Retrieves the challenger address for a given v1 game + function getChallengerV1(IPermissionedDisputeGame _disputeGame) internal view returns (address) { return _disputeGame.challenger(); } + /// @notice Retrieves the challenger address of a given v1 or v2 game + function getChallenger( + IDisputeGameFactory _disputeGameFactory, + IPermissionedDisputeGame _disputeGame, + GameType _gameType + ) + internal + view + returns (address) + { + bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); + if (gameArgsBytes.length == 0) { + return _disputeGame.challenger(); + } else { + return LibGameArgs.decode(gameArgsBytes).challenger; + } + } + /// @notice Helper function to register permissioned game V2 implementation /// @dev Extracted to avoid stack too deep error /// @param _input The deployment input data containing all necessary parameters @@ -571,8 +607,8 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { getAnchorStateRegistry(gameConfig.systemConfig), gameL2ChainId ), - getProposer(IPermissionedDisputeGame(address(existingGame))), - getChallenger(IPermissionedDisputeGame(address(existingGame))) + getProposerV1(IPermissionedDisputeGame(address(existingGame))), + getChallengerV1(IPermissionedDisputeGame(address(existingGame))) ); } else { constructorData = encodePermissionlessFDGConstructor( @@ -1006,8 +1042,8 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { IDisputeGame newGame; if (GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON)) { - address proposer = getProposer(IPermissionedDisputeGame(address(_disputeGame))); - address challenger = getChallenger(IPermissionedDisputeGame(address(_disputeGame))); + address proposer = getProposerV1(IPermissionedDisputeGame(address(_disputeGame))); + address challenger = getChallengerV1(IPermissionedDisputeGame(address(_disputeGame))); newGame = IDisputeGame( Blueprint.deployFrom( bps.permissionedDisputeGame1, @@ -1057,15 +1093,13 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { ) internal { + IDisputeGameFactory disputeGameFactory = + IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); // If the prestate is set in the config, use it. If not set, we'll try to use the prestate // that already exists on the current dispute game. Claim absolutePrestate; if (Claim.unwrap(_opChainConfig.absolutePrestate) == bytes32(0)) { - absolutePrestate = getAbsolutePrestate( - IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()), - address(_disputeGame), - _gameType - ); + absolutePrestate = getAbsolutePrestate(disputeGameFactory, address(_disputeGame), _gameType); } else { absolutePrestate = _opChainConfig.absolutePrestate; } @@ -1079,8 +1113,10 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { bytes memory gameArgs; if (GameType.unwrap(_gameType) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON)) { newGame = IDisputeGame(_impls.permissionedDisputeGameV2Impl); - address proposer = getProposer(IPermissionedDisputeGame(address(_disputeGame))); - address challenger = getChallenger(IPermissionedDisputeGame(address(_disputeGame))); + address proposer = + getProposer(disputeGameFactory, IPermissionedDisputeGame(address(_disputeGame)), _gameType); + address challenger = + getChallenger(disputeGameFactory, IPermissionedDisputeGame(address(_disputeGame)), _gameType); gameArgs = abi.encodePacked( absolutePrestate, // 32 bytes _impls.mipsImpl, // 20 bytes @@ -1101,8 +1137,7 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { ); } - IDisputeGameFactory dgf = IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); - setDGFImplementation(dgf, _gameType, IDisputeGame(newGame), gameArgs); + setDGFImplementation(disputeGameFactory, _gameType, IDisputeGame(newGame), gameArgs); } /// @notice Retrieves the absolute prestate for a dispute game, handling both V1 and V2 games. diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 029adab2a7f..119f74c6045 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -356,6 +356,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { ); (,,,, Claim rootClaim,,) = game.claimData(0); + vm.assertEq(GameTypes.PERMISSIONED_CANNON.raw(), game.gameType().raw()); vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); vm.assertEq(l2ChainId, game.l2ChainId()); From 41420088e8bf2e5e3a17fe46408bc61fbd81b855 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 17 Oct 2025 12:27:05 -0400 Subject: [PATCH 11/15] assert deployed CANNON game parameters --- .../test/L1/OPContractsManager.t.sol | 65 ++++++++++--------- .../test/setup/ForkLive.s.sol | 3 +- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 119f74c6045..f035204d6c7 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -112,7 +112,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { struct PreUpgradeState { Claim cannonAbsolutePrestate; Claim permissionedAbsolutePrestate; - IDelayedWETH cannonWethProxy; + IDelayedWETH permissionlessWethProxy; IDelayedWETH permissionedCannonWethProxy; } @@ -167,7 +167,7 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { permissionedAbsolutePrestate: IPermissionedDisputeGame( address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)) ).absolutePrestate(), - cannonWethProxy: delayedWeth, + permissionlessWethProxy: delayedWeth, permissionedCannonWethProxy: delayedWETHPermissionedGameProxy }); @@ -345,33 +345,40 @@ contract OPContractsManager_Upgrade_Harness is CommonTest { (, uint256 rootBlockNumber) = optimismPortal2.anchorStateRegistry().getAnchorRoot(); uint256 l2BlockNumber = rootBlockNumber + 1; - // Deploy a live game and ensure it's configured correctly. - vm.prank(expectedProposer, expectedProposer); - IPermissionedDisputeGame game = IPermissionedDisputeGame( - address( - disputeGameFactory.create{ value: bondAmount }( - GameTypes.PERMISSIONED_CANNON, claim, abi.encode(l2BlockNumber) - ) - ) - ); - (,,,, Claim rootClaim,,) = game.claimData(0); - - vm.assertEq(GameTypes.PERMISSIONED_CANNON.raw(), game.gameType().raw()); - vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); - vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); - vm.assertEq(l2ChainId, game.l2ChainId()); - vm.assertEq(302400, game.maxClockDuration().raw()); - vm.assertEq(10800, game.clockExtension().raw()); - vm.assertEq(73, game.maxGameDepth()); - vm.assertEq(30, game.splitDepth()); - vm.assertEq(l2BlockNumber, game.l2BlockNumber()); - vm.assertEq(_challenger, game.challenger()); - vm.assertEq(expectedProposer, game.proposer()); - vm.assertEq(expectedVm, address(game.vm())); - vm.assertEq(address(preUpgradeState.permissionedCannonWethProxy), address(game.weth())); - vm.assertEq(expectedProposer, game.gameCreator()); - vm.assertEq(claim.raw(), rootClaim.raw()); - vm.assertEq(blockhash(block.number - 1), game.l1Head().raw()); + // Deploy live games and ensure they're configured correctly + GameType[] memory gameTypes = new GameType[](2); + gameTypes[0] = GameTypes.PERMISSIONED_CANNON; + gameTypes[1] = GameTypes.CANNON; + for (uint256 i = 0; i < gameTypes.length; i++) { + GameType gt = gameTypes[i]; + vm.prank(expectedProposer, expectedProposer); + IPermissionedDisputeGame game = IPermissionedDisputeGame( + address(disputeGameFactory.create{ value: bondAmount }(gt, claim, abi.encode(l2BlockNumber))) + ); + (,,,, Claim rootClaim,,) = game.claimData(0); + + vm.assertEq(gt.raw(), game.gameType().raw()); + vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); + vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); + vm.assertEq(l2ChainId, game.l2ChainId()); + vm.assertEq(302400, game.maxClockDuration().raw()); + vm.assertEq(10800, game.clockExtension().raw()); + vm.assertEq(73, game.maxGameDepth()); + vm.assertEq(30, game.splitDepth()); + vm.assertEq(l2BlockNumber, game.l2BlockNumber()); + vm.assertEq(expectedVm, address(game.vm())); + vm.assertEq(expectedProposer, game.gameCreator()); + vm.assertEq(claim.raw(), rootClaim.raw()); + vm.assertEq(blockhash(block.number - 1), game.l1Head().raw()); + + if (gt.raw() == GameTypes.PERMISSIONED_CANNON.raw()) { + vm.assertEq(address(preUpgradeState.permissionedCannonWethProxy), address(game.weth())); + vm.assertEq(_challenger, game.challenger()); + vm.assertEq(expectedProposer, game.proposer()); + } else { + vm.assertEq(address(preUpgradeState.permissionlessWethProxy), address(game.weth())); + } + } } /// @notice Executes all past upgrades that have not yet been executed on mainnet as of the diff --git a/packages/contracts-bedrock/test/setup/ForkLive.s.sol b/packages/contracts-bedrock/test/setup/ForkLive.s.sol index 146a25466b8..7835c6a38cf 100644 --- a/packages/contracts-bedrock/test/setup/ForkLive.s.sol +++ b/packages/contracts-bedrock/test/setup/ForkLive.s.sol @@ -169,8 +169,7 @@ contract ForkLive is Deployer, StdAssertions { artifacts.save("MipsSingleton", vm.parseTomlAddress(opToml, ".addresses.MIPS")); IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); - IFaultDisputeGame faultDisputeGame = - IFaultDisputeGame(opToml.readAddressOr(".addresses.FaultDisputeGame", address(0))); + IFaultDisputeGame faultDisputeGame = IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))); artifacts.save("FaultDisputeGame", address(faultDisputeGame)); artifacts.save("PermissionlessDelayedWETHProxy", address(faultDisputeGame.weth())); From c86923793f843e9bc8a4887f3b8a0c4a0f9501c0 Mon Sep 17 00:00:00 2001 From: inphi Date: Fri, 17 Oct 2025 16:50:10 -0400 Subject: [PATCH 12/15] use v2 getters --- .../snapshots/semver-lock.json | 2 +- .../src/L1/OPContractsManager.sol | 101 ++++++++++++------ 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index a4eadbc8761..0447a19a553 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,7 +21,7 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0x53926724bed6040c04befbf072fa42c0ce025f395bd3aeb9efe7f95afea00e1c" + "sourceCodeHash": "0xef436ed26677703c8f036ee82f8bd2067469c4d10dde6afc5f0e286d786ce95f" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x94f761c9648b31ab4d8dff3278df45a17e1fa02cc146ae46db4944bc61f5d2af", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 70f633eeb7c..d922ac61af5 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -287,11 +287,29 @@ abstract contract OPContractsManagerBase { return _disputeGameFactory.gameImpls(_gameType); } - /// @notice Retrieves the Anchor State Registry for a given game - function getAnchorStateRegistry(IFaultDisputeGame _disputeGame) internal view returns (IAnchorStateRegistry) { + /// @notice Retrieves the Anchor State Registry for a given v1 game + function getAnchorStateRegistryV1(IFaultDisputeGame _disputeGame) internal view returns (IAnchorStateRegistry) { return _disputeGame.anchorStateRegistry(); } + /// @notice Retrieves the Anchor State Registry for a given v1 or v2 game + function getAnchorStateRegistry( + IDisputeGameFactory _disputeGameFactory, + IDisputeGame _disputeGame, + GameType _gameType + ) + internal + view + returns (IAnchorStateRegistry) + { + bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); + if (gameArgsBytes.length == 0) { + return IFaultDisputeGame(address(_disputeGame)).anchorStateRegistry(); + } else { + return IAnchorStateRegistry(LibGameArgs.decode(gameArgsBytes).anchorStateRegistry); + } + } + /// @notice Retrieves the L2 chain ID for a given game function getL2ChainId(IFaultDisputeGame _disputeGame) internal view returns (uint256) { return _disputeGame.l2ChainId(); @@ -305,7 +323,7 @@ abstract contract OPContractsManagerBase { /// @notice Retrieves the proposer address for a given v1 or v2 game function getProposer( IDisputeGameFactory _disputeGameFactory, - IPermissionedDisputeGame _disputeGame, + IDisputeGame _disputeGame, GameType _gameType ) internal @@ -314,7 +332,7 @@ abstract contract OPContractsManagerBase { { bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); if (gameArgsBytes.length == 0) { - return _disputeGame.proposer(); + return IPermissionedDisputeGame(address(_disputeGame)).proposer(); } else { return LibGameArgs.decode(gameArgsBytes).proposer; } @@ -328,7 +346,7 @@ abstract contract OPContractsManagerBase { /// @notice Retrieves the challenger address of a given v1 or v2 game function getChallenger( IDisputeGameFactory _disputeGameFactory, - IPermissionedDisputeGame _disputeGame, + IDisputeGame _disputeGame, GameType _gameType ) internal @@ -337,7 +355,7 @@ abstract contract OPContractsManagerBase { { bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); if (gameArgsBytes.length == 0) { - return _disputeGame.challenger(); + return IPermissionedDisputeGame(address(_disputeGame)).challenger(); } else { return LibGameArgs.decode(gameArgsBytes).challenger; } @@ -378,7 +396,7 @@ abstract contract OPContractsManagerBase { } /// @notice Retrieves the AnchorStateRegistry address for a given SystemConfig - function getAnchorStateRegistry(ISystemConfig _systemConfig) internal view returns (IAnchorStateRegistry) { + function getAnchorStateRegistryV1(ISystemConfig _systemConfig) internal view returns (IAnchorStateRegistry) { return IAnchorStateRegistry(IOptimismPortal(payable(_systemConfig.optimismPortal())).anchorStateRegistry()); } @@ -414,17 +432,35 @@ abstract contract OPContractsManagerBase { clockExtension: _disputeGame.clockExtension(), maxClockDuration: _disputeGame.maxClockDuration(), vm: _disputeGame.vm(), - weth: getWETH(_disputeGame), - anchorStateRegistry: getAnchorStateRegistry(_disputeGame), + weth: getWETHV1(_disputeGame), + anchorStateRegistry: getAnchorStateRegistryV1(_disputeGame), l2ChainId: l2ChainId }); } - /// @notice Retrieves the DelayedWETH address for a given game - function getWETH(IFaultDisputeGame _disputeGame) internal view returns (IDelayedWETH) { + /// @notice Retrieves the DelayedWETH address for a given v1 game + function getWETHV1(IFaultDisputeGame _disputeGame) internal view returns (IDelayedWETH) { return _disputeGame.weth(); } + /// @notice Retrieves the DelayedWETH for a given v1 or v2 game + function getWETH( + IDisputeGameFactory _disputeGameFactory, + IDisputeGame _disputeGame, + GameType _gameType + ) + internal + view + returns (IDelayedWETH) + { + bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); + if (gameArgsBytes.length == 0) { + return IFaultDisputeGame(address(_disputeGame)).weth(); + } else { + return IDelayedWETH(payable(LibGameArgs.decode(gameArgsBytes).weth)); + } + } + /// @notice Sets a game implementation on the dispute game factory /// @param _dgf The dispute game factory /// @param _gameType The game type @@ -604,7 +640,7 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { gameConfig.disputeMaxClockDuration, gameConfig.vm, outputs[i].delayedWETH, - getAnchorStateRegistry(gameConfig.systemConfig), + getAnchorStateRegistryV1(gameConfig.systemConfig), gameL2ChainId ), getProposerV1(IPermissionedDisputeGame(address(existingGame))), @@ -621,7 +657,7 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { gameConfig.disputeMaxClockDuration, gameConfig.vm, outputs[i].delayedWETH, - getAnchorStateRegistry(gameConfig.systemConfig), + getAnchorStateRegistryV1(gameConfig.systemConfig), gameL2ChainId ) ); @@ -903,33 +939,33 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { } // All chains have the PermissionedDisputeGame, grab that. - IPermissionedDisputeGame permissionedDisputeGame = - IPermissionedDisputeGame(address(getGameImplementation(dgf, GameTypes.PERMISSIONED_CANNON))); + IDisputeGame permissionedDisputeGame = getGameImplementation(dgf, GameTypes.PERMISSIONED_CANNON); if (!isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { // Update the PermissionedDisputeGame. // We're reusing the same DelayedWETH and ASR contracts. deployAndSetNewGameImpl({ _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionedDisputeGame)), - _newDelayedWeth: permissionedDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionedDisputeGame.anchorStateRegistry(), + _disputeGame: permissionedDisputeGame, + _newDelayedWeth: getWETH(dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON), + _newAnchorStateRegistryProxy: getAnchorStateRegistry( + dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON + ), _gameType: GameTypes.PERMISSIONED_CANNON, _opChainConfig: _opChainConfig }); // Now retrieve the permissionless game. - IFaultDisputeGame permissionlessDisputeGame = - IFaultDisputeGame(address(getGameImplementation(dgf, GameTypes.CANNON))); + IDisputeGame permissionlessDisputeGame = getGameImplementation(dgf, GameTypes.CANNON); // If it exists, replace its implementation. // We're reusing the same DelayedWETH and ASR contracts. if (address(permissionlessDisputeGame) != address(0)) { deployAndSetNewGameImpl({ _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionlessDisputeGame)), - _newDelayedWeth: permissionlessDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionlessDisputeGame.anchorStateRegistry(), + _disputeGame: permissionlessDisputeGame, + _newDelayedWeth: getWETH(dgf, permissionlessDisputeGame, GameTypes.CANNON), + _newAnchorStateRegistryProxy: getAnchorStateRegistry(dgf, permissionlessDisputeGame, GameTypes.CANNON), _gameType: GameTypes.CANNON, _opChainConfig: _opChainConfig }); @@ -938,15 +974,18 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { setNewGameImplV2({ _impls: _impls, _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionedDisputeGame)), - _newDelayedWeth: permissionedDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionedDisputeGame.anchorStateRegistry(), + _disputeGame: permissionedDisputeGame, + _newDelayedWeth: getWETH( + dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON + ), + _newAnchorStateRegistryProxy: getAnchorStateRegistry( + dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON + ), _gameType: GameTypes.PERMISSIONED_CANNON, _opChainConfig: _opChainConfig }); - IFaultDisputeGame permissionlessDisputeGame = - IFaultDisputeGame(address(getGameImplementation(dgf, GameTypes.CANNON))); + IDisputeGame permissionlessDisputeGame = getGameImplementation(dgf, GameTypes.CANNON); // If it exists, replace its implementation. // We're reusing the same DelayedWETH and ASR contracts. @@ -954,9 +993,9 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { setNewGameImplV2({ _impls: _impls, _l2ChainId: _l2ChainId, - _disputeGame: IDisputeGame(address(permissionlessDisputeGame)), - _newDelayedWeth: permissionlessDisputeGame.weth(), - _newAnchorStateRegistryProxy: permissionlessDisputeGame.anchorStateRegistry(), + _disputeGame: permissionlessDisputeGame, + _newDelayedWeth: getWETH(dgf, permissionlessDisputeGame, GameTypes.CANNON), + _newAnchorStateRegistryProxy: getAnchorStateRegistry(dgf, permissionlessDisputeGame, GameTypes.CANNON), _gameType: GameTypes.CANNON, _opChainConfig: _opChainConfig }); From ff2fa93da2a7e499f4209640939eb2c7a331b9fc Mon Sep 17 00:00:00 2001 From: inphi Date: Sun, 19 Oct 2025 14:47:50 -0400 Subject: [PATCH 13/15] review comments --- .../contracts-bedrock/snapshots/semver-lock.json | 4 ++-- .../contracts-bedrock/src/L1/OPContractsManager.sol | 4 +--- .../src/dispute/lib/LibGameArgs.sol | 11 +++++++---- .../test/dispute/lib/LibGameArgs.t.sol | 12 +++++++----- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 0447a19a553..0129278f625 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,10 +21,10 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0xef436ed26677703c8f036ee82f8bd2067469c4d10dde6afc5f0e286d786ce95f" + "sourceCodeHash": "0x01010fcc469ee5b75a446557ed1dd8e202ad5acd2bc23c7ccc8d7117e714d302" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0x94f761c9648b31ab4d8dff3278df45a17e1fa02cc146ae46db4944bc61f5d2af", + "initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc", "sourceCodeHash": "0x30d7e4243a3bab7fea8504be2cd24f2c5ab3335b802d62282a374a458a08feec" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index d922ac61af5..a6af2b986f9 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -975,9 +975,7 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { _impls: _impls, _l2ChainId: _l2ChainId, _disputeGame: permissionedDisputeGame, - _newDelayedWeth: getWETH( - dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON - ), + _newDelayedWeth: getWETH(dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON), _newAnchorStateRegistryProxy: getAnchorStateRegistry( dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON ), diff --git a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol index 32395d40c11..3af71d317ad 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibGameArgs.sol @@ -6,6 +6,9 @@ import { InvalidGameArgsLength } from "src/dispute/lib/Errors.sol"; /// @title LibGameArgs /// @notice Library for decoding the game arguments used in dispute games. library LibGameArgs { + uint256 public constant PERMISSIONLESS_ARGS_LENGTH = 124; + uint256 public constant PERMISSIONED_ARGS_LENGTH = 164; + /// @notice Struct representing the game arguments. struct GameArgs { bytes32 absolutePrestate; @@ -21,7 +24,7 @@ library LibGameArgs { /// @param _gameArgs The bytes array containing the encoded game arguments. function decode(bytes memory _gameArgs) internal pure returns (GameArgs memory) { uint256 len = _gameArgs.length; - if (len != 164 && len != 124) { + if (len != PERMISSIONED_ARGS_LENGTH && len != PERMISSIONLESS_ARGS_LENGTH) { revert InvalidGameArgsLength(); } @@ -43,7 +46,7 @@ library LibGameArgs { l2ChainId := mload(add(d, 92)) } - if (len == 164) { + if (len == PERMISSIONED_ARGS_LENGTH) { assembly { // skip length prefix let d := add(_gameArgs, 32) @@ -64,11 +67,11 @@ library LibGameArgs { /// @notice Checks if the provided game arguments are valid for a permissionless game. function isValidPermissionlessArgs(bytes memory _args) internal pure returns (bool) { - return _args.length == 124; + return _args.length == PERMISSIONLESS_ARGS_LENGTH; } /// @notice Checks if the provided game arguments are valid for a permissioned game. function isValidPermissionedArgs(bytes memory _args) internal pure returns (bool) { - return _args.length == 164; + return _args.length == PERMISSIONED_ARGS_LENGTH; } } diff --git a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol index 0f6ee1e429b..1f7e732e618 100644 --- a/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol +++ b/packages/contracts-bedrock/test/dispute/lib/LibGameArgs.t.sol @@ -104,23 +104,25 @@ contract LibGameArgs_Decode_Test is Test { } function testFuzz_decode_invalidLength_reverts(bytes memory _buf) public { - bool ok = (_buf.length == 124 || _buf.length == 164); + bool ok = ( + _buf.length == LibGameArgs.PERMISSIONLESS_ARGS_LENGTH || _buf.length == LibGameArgs.PERMISSIONED_ARGS_LENGTH + ); vm.assume(!ok); vm.expectRevert(InvalidGameArgsLength.selector); harness.decode(_buf); } function test_isValidPermissionlessArgs_works() public pure { - bytes memory validBuf = new bytes(124); + bytes memory validBuf = new bytes(LibGameArgs.PERMISSIONLESS_ARGS_LENGTH); assertTrue(LibGameArgs.isValidPermissionlessArgs(validBuf)); - validBuf = new bytes(164); + validBuf = new bytes(LibGameArgs.PERMISSIONED_ARGS_LENGTH); assertFalse(LibGameArgs.isValidPermissionlessArgs(validBuf)); } function test_isValidPermissionedArgs_works() public pure { - bytes memory validBuf = new bytes(164); + bytes memory validBuf = new bytes(LibGameArgs.PERMISSIONED_ARGS_LENGTH); assertTrue(LibGameArgs.isValidPermissionedArgs(validBuf)); - validBuf = new bytes(124); + validBuf = new bytes(LibGameArgs.PERMISSIONLESS_ARGS_LENGTH); assertFalse(LibGameArgs.isValidPermissionedArgs(validBuf)); } } From b45d83c3a3f82c18dfd67610499431d8690503a5 Mon Sep 17 00:00:00 2001 From: inphi Date: Sun, 19 Oct 2025 22:25:49 -0400 Subject: [PATCH 14/15] fix asr getter name --- packages/contracts-bedrock/snapshots/semver-lock.json | 2 +- packages/contracts-bedrock/src/L1/OPContractsManager.sol | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 0129278f625..aa41a8c5c24 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,7 +21,7 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0x01010fcc469ee5b75a446557ed1dd8e202ad5acd2bc23c7ccc8d7117e714d302" + "sourceCodeHash": "0x4df4f706ece6d6c521a2fe636b632ba06c6ecea160136ea47be9f80f60dc973c" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index a6af2b986f9..ca686a0fa19 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -396,7 +396,7 @@ abstract contract OPContractsManagerBase { } /// @notice Retrieves the AnchorStateRegistry address for a given SystemConfig - function getAnchorStateRegistryV1(ISystemConfig _systemConfig) internal view returns (IAnchorStateRegistry) { + function getAnchorStateRegistry(ISystemConfig _systemConfig) internal view returns (IAnchorStateRegistry) { return IAnchorStateRegistry(IOptimismPortal(payable(_systemConfig.optimismPortal())).anchorStateRegistry()); } @@ -640,7 +640,7 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { gameConfig.disputeMaxClockDuration, gameConfig.vm, outputs[i].delayedWETH, - getAnchorStateRegistryV1(gameConfig.systemConfig), + getAnchorStateRegistry(gameConfig.systemConfig), gameL2ChainId ), getProposerV1(IPermissionedDisputeGame(address(existingGame))), @@ -657,7 +657,7 @@ contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { gameConfig.disputeMaxClockDuration, gameConfig.vm, outputs[i].delayedWETH, - getAnchorStateRegistryV1(gameConfig.systemConfig), + getAnchorStateRegistry(gameConfig.systemConfig), gameL2ChainId ) ); From 157c4310e893587233ca16f0c733762a43feaf16 Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 20 Oct 2025 10:46:38 -0400 Subject: [PATCH 15/15] use v1 functions for existing upgrade path --- .../contracts-bedrock/snapshots/semver-lock.json | 2 +- .../contracts-bedrock/src/L1/OPContractsManager.sol | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index aa41a8c5c24..f8916896caf 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -21,7 +21,7 @@ }, "src/L1/OPContractsManager.sol:OPContractsManager": { "initCodeHash": "0xc6a5146f158bc14297447cda1668f83e8dbfdd74f1b8bc2291d9626933bd23ad", - "sourceCodeHash": "0x4df4f706ece6d6c521a2fe636b632ba06c6ecea160136ea47be9f80f60dc973c" + "sourceCodeHash": "0xd883ebfcc637ba9c6de12a872015098614cd288aaee84cda9d4c746aa1dcba18" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x2eaa345ba05582c67b40a1eb7ec9d54823aa08468e697e2d6c04bb74cc574abc", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index ca686a0fa19..b662cbfc672 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -947,10 +947,8 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { deployAndSetNewGameImpl({ _l2ChainId: _l2ChainId, _disputeGame: permissionedDisputeGame, - _newDelayedWeth: getWETH(dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON), - _newAnchorStateRegistryProxy: getAnchorStateRegistry( - dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON - ), + _newDelayedWeth: getWETHV1(IFaultDisputeGame(address(permissionedDisputeGame))), + _newAnchorStateRegistryProxy: getAnchorStateRegistryV1(IFaultDisputeGame(address(permissionedDisputeGame))), _gameType: GameTypes.PERMISSIONED_CANNON, _opChainConfig: _opChainConfig }); @@ -964,8 +962,10 @@ contract OPContractsManagerUpgrader is OPContractsManagerBase { deployAndSetNewGameImpl({ _l2ChainId: _l2ChainId, _disputeGame: permissionlessDisputeGame, - _newDelayedWeth: getWETH(dgf, permissionlessDisputeGame, GameTypes.CANNON), - _newAnchorStateRegistryProxy: getAnchorStateRegistry(dgf, permissionlessDisputeGame, GameTypes.CANNON), + _newDelayedWeth: getWETHV1(IFaultDisputeGame(address(permissionlessDisputeGame))), + _newAnchorStateRegistryProxy: getAnchorStateRegistryV1( + IFaultDisputeGame(address(permissionlessDisputeGame)) + ), _gameType: GameTypes.CANNON, _opChainConfig: _opChainConfig });