diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index 35220cb008d61..a2343838eda13 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -12,7 +12,6 @@ import { Deployer } from "scripts/deploy/Deployer.sol"; import { Chains } from "scripts/libraries/Chains.sol"; import { Config } from "scripts/libraries/Config.sol"; import { StateDiff } from "scripts/libraries/StateDiff.sol"; -import { Process } from "scripts/libraries/Process.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { DeploySuperchain2 } from "scripts/deploy/DeploySuperchain2.s.sol"; @@ -30,8 +29,6 @@ import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; @@ -373,8 +370,6 @@ contract Deploy is Deployer { _implementation: delayedWETHImpl, _data: abi.encodeCall(IDelayedWETH.initialize, (deployOutput.systemConfigProxy)) }); - - setCannonFaultGameImplementation(); } //////////////////////////////////////////////////////////////// @@ -406,83 +401,6 @@ contract Deploy is Deployer { addr_ = address(proxy); } - /////////////////////////////////////////////////////////// - // Proofs setup helper functions // - /////////////////////////////////////////////////////////// - - /// @notice Load the appropriate mips absolute prestate for devenets depending on config environment. - function loadMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { - if (block.chainid == Chains.LocalDevnet || block.chainid == Chains.GethDevnet) { - return _loadDevnetMtMipsAbsolutePrestate(); - } else { - console.log( - "[Cannon Dispute Game] Using absolute prestate from config: %x", cfg.faultGameAbsolutePrestate() - ); - mipsAbsolutePrestate_ = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())); - } - } - - function loadInteropDevnetAbsolutePrestate() internal returns (Claim interopDevnetAbsolutePrestate_) { - string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-interop.json"); - if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) { - revert( - "Deploy: cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root" - ); - } - interopDevnetAbsolutePrestate_ = - Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32))); - console.log( - "[Cannon Dispute Game] Using devnet Interop Devnet Absolute Prestate: %s", - vm.toString(Claim.unwrap(interopDevnetAbsolutePrestate_)) - ); - } - - /// @notice Loads the multithreaded mips absolute prestate from the prestate-proof-mt64 for devnets otherwise - /// from the config. - function _loadDevnetMtMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { - // Fetch the absolute prestate dump - string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-mt64.json"); - if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) { - revert( - "Deploy: MT-Cannon prestate dump not found, generate it with `make cannon-prestate-mt64` in the monorepo root" - ); - } - mipsAbsolutePrestate_ = - Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32))); - console.log( - "[MT-Cannon Dispute Game] Using devnet MIPS64 Absolute prestate: %s", - vm.toString(Claim.unwrap(mipsAbsolutePrestate_)) - ); - } - - /// @notice Sets the implementation for the `CANNON` game type in the `DisputeGameFactory` - function setCannonFaultGameImplementation() public { - console.log("Setting Cannon FaultDisputeGame implementation"); - address opcm = artifacts.mustGetAddress("OPContractsManager"); - IProxyAdmin proxyAdmin = IProxyAdmin(artifacts.mustGetAddress("ProxyAdmin")); - - IOPContractsManager.AddGameInput[] memory addGameInput = new IOPContractsManager.AddGameInput[](1); - addGameInput[0] = IOPContractsManager.AddGameInput({ - saltMixer: "CannonFaultGame", - systemConfig: ISystemConfig(artifacts.mustGetAddress("SystemConfigProxy")), - proxyAdmin: proxyAdmin, - delayedWETH: IDelayedWETH(artifacts.mustGetAddress("DelayedWETHProxy")), - disputeGameType: GameTypes.CANNON, - disputeAbsolutePrestate: loadMipsAbsolutePrestate(), - disputeMaxGameDepth: cfg.faultGameMaxDepth(), - disputeSplitDepth: cfg.faultGameSplitDepth(), - disputeClockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())), - disputeMaxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), - initialBond: 0.08 ether, - vm: IBigStepper(artifacts.mustGetAddress("MipsSingleton")), - permissioned: false - }); - - vm.prank(cfg.finalSystemOwner(), true); - (bool success,) = opcm.delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (addGameInput))); - require(success, "Deploy: Cannon FaultDisputeGame implementation not set"); - } - /// @notice Get the DeployInput struct to use for testing function getDeployInput() public view returns (IOPContractsManager.DeployInput memory) { string memory saltMixer = "salt mixer"; diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol index 69efa03a0fe62..c0afc78973618 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol @@ -9,6 +9,7 @@ import { console2 as console } from "forge-std/console2.sol"; import { CommonTest } from "test/setup/CommonTest.sol"; import { NextImpl } from "test/mocks/NextImpl.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; +import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; // Scripts import { ForgeArtifacts, StorageSlot } from "scripts/libraries/ForgeArtifacts.sol"; @@ -463,7 +464,7 @@ contract OptimismPortal2_Test is CommonTest { } } -contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { +contract OptimismPortal2_FinalizeWithdrawal_Test is DisputeGameFactory_Init { // Reusable default values for a test withdrawal Types.WithdrawalTransaction _defaultTx; IFaultDisputeGame game; @@ -521,6 +522,8 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { _proposedBlockNumber = 0xFF; } + setupFaultDisputeGame(Claim.wrap(_outputRoot)); + // Warp forward in time to ensure that the game is created after the retirement timestamp. vm.warp(anchorStateRegistry.retirementTimestamp() + 1); diff --git a/packages/contracts-bedrock/test/dispute/DisputeGameFactory.t.sol b/packages/contracts-bedrock/test/dispute/DisputeGameFactory.t.sol index 255496e8f4d10..2afdff39b74f1 100644 --- a/packages/contracts-bedrock/test/dispute/DisputeGameFactory.t.sol +++ b/packages/contracts-bedrock/test/dispute/DisputeGameFactory.t.sol @@ -6,6 +6,7 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Scripts import { ForgeArtifacts, StorageSlot } from "scripts/libraries/ForgeArtifacts.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; // Libraries import "src/dispute/lib/Types.sol"; @@ -15,6 +16,13 @@ import "src/dispute/lib/Errors.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { IProxyAdminOwnedBase } from "interfaces/L1/IProxyAdminOwnedBase.sol"; +import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol"; +import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; +import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol"; +import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; +import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol"; +// Mocks +import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; contract DisputeGameFactory_Init is CommonTest { FakeClone fakeClone; @@ -31,6 +39,154 @@ contract DisputeGameFactory_Init is CommonTest { vm.prank(disputeGameFactory.owner()); disputeGameFactory.transferOwnership(address(this)); } + + /// @notice Creates a new VM instance with the given absolute prestate + function _createVM(Claim _absolutePrestate) internal returns (AlphabetVM vm_, IPreimageOracle preimageOracle_) { + // Set preimage oracle challenge period to something arbitrary (4 seconds) just so we can + // actually test the clock extensions later on. This is not a realistic value. + preimageOracle_ = IPreimageOracle( + DeployUtils.create1({ + _name: "PreimageOracle", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 4))) + }) + ); + vm_ = new AlphabetVM(_absolutePrestate, preimageOracle_); + } + + function _getGameConstructorParams( + Claim _absolutePrestate, + AlphabetVM _vm, + GameType _gameType + ) + internal + view + returns (IFaultDisputeGame.GameConstructorParams memory params_) + { + return IFaultDisputeGame.GameConstructorParams({ + gameType: _gameType, + absolutePrestate: _absolutePrestate, + maxGameDepth: 2 ** 3, + splitDepth: 2 ** 2, + clockExtension: Duration.wrap(3 hours), + maxClockDuration: Duration.wrap(3.5 days), + vm: _vm, + weth: delayedWeth, + anchorStateRegistry: anchorStateRegistry, + l2ChainId: 0 + }); + } + + function _getSuperGameConstructorParams( + Claim _absolutePrestate, + AlphabetVM _vm, + GameType _gameType + ) + private + view + returns (ISuperFaultDisputeGame.GameConstructorParams memory params_) + { + bytes memory args = abi.encode(_getGameConstructorParams(_absolutePrestate, _vm, _gameType)); + params_ = abi.decode(args, (ISuperFaultDisputeGame.GameConstructorParams)); + } + + function _setGame(address _gameImpl, GameType _gameType) internal { + vm.startPrank(disputeGameFactory.owner()); + disputeGameFactory.setImplementation(_gameType, IDisputeGame(_gameImpl)); + disputeGameFactory.setInitBond(_gameType, 0.08 ether); + vm.stopPrank(); + } + + /// @notice Sets up a super cannon game implementation + function setupSuperFaultDisputeGame(Claim _absolutePrestate) + internal + returns (address gameImpl_, AlphabetVM vm_, IPreimageOracle preimageOracle_) + { + (vm_, preimageOracle_) = _createVM(_absolutePrestate); + + gameImpl_ = DeployUtils.create1({ + _name: "SuperFaultDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + ISuperFaultDisputeGame.__constructor__, + (_getSuperGameConstructorParams(_absolutePrestate, vm_, GameTypes.SUPER_CANNON)) + ) + ) + }); + + _setGame(gameImpl_, GameTypes.SUPER_CANNON); + } + + /// @notice Sets up a super permissioned game implementation + function setupSuperPermissionedDisputeGame( + Claim _absolutePrestate, + address _proposer, + address _challenger + ) + internal + returns (address gameImpl_, AlphabetVM vm_, IPreimageOracle preimageOracle_) + { + (vm_, preimageOracle_) = _createVM(_absolutePrestate); + + gameImpl_ = DeployUtils.create1({ + _name: "SuperPermissionedDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + ISuperPermissionedDisputeGame.__constructor__, + ( + _getSuperGameConstructorParams(_absolutePrestate, vm_, GameTypes.SUPER_PERMISSIONED_CANNON), + _proposer, + _challenger + ) + ) + ) + }); + + _setGame(gameImpl_, GameTypes.SUPER_PERMISSIONED_CANNON); + } + + /// @notice Sets up a fault game implementation + function setupFaultDisputeGame(Claim _absolutePrestate) + internal + returns (address gameImpl_, AlphabetVM vm_, IPreimageOracle preimageOracle_) + { + (vm_, preimageOracle_) = _createVM(_absolutePrestate); + gameImpl_ = DeployUtils.create1({ + _name: "FaultDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + IFaultDisputeGame.__constructor__, (_getGameConstructorParams(_absolutePrestate, vm_, GameTypes.CANNON)) + ) + ) + }); + + _setGame(gameImpl_, GameTypes.CANNON); + } + + function setupPermissionedDisputeGame( + Claim _absolutePrestate, + address _proposer, + address _challenger + ) + internal + returns (address gameImpl_, AlphabetVM vm_, IPreimageOracle preimageOracle_) + { + (vm_, preimageOracle_) = _createVM(_absolutePrestate); + gameImpl_ = DeployUtils.create1({ + _name: "PermissionedDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + IPermissionedDisputeGame.__constructor__, + ( + _getGameConstructorParams(_absolutePrestate, vm_, GameTypes.PERMISSIONED_CANNON), + _proposer, + _challenger + ) + ) + ) + }); + + _setGame(gameImpl_, GameTypes.PERMISSIONED_CANNON); + } } contract DisputeGameFactory_initialize_Test is DisputeGameFactory_Init { diff --git a/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol b/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol index 4a30032c0ffed..a4bf23fd06848 100644 --- a/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol @@ -58,46 +58,8 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init { // Set the extra data for the game creation extraData = abi.encode(l2BlockNumber); - // Set preimage oracle challenge period to something arbitrary (4 seconds) just so we can - // actually test the clock extensions later on. This is not a realistic value. - AlphabetVM _vm = new AlphabetVM( - absolutePrestate, - IPreimageOracle( - DeployUtils.create1({ - _name: "PreimageOracle", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 4))) - }) - ) - ); - - // Deploy an implementation of the fault game - gameImpl = IFaultDisputeGame( - DeployUtils.create1({ - _name: "FaultDisputeGame", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IFaultDisputeGame.__constructor__, - ( - IFaultDisputeGame.GameConstructorParams({ - gameType: GAME_TYPE, - absolutePrestate: absolutePrestate, - maxGameDepth: 2 ** 3, - splitDepth: 2 ** 2, - clockExtension: Duration.wrap(3 hours), - maxClockDuration: Duration.wrap(3.5 days), - vm: _vm, - weth: delayedWeth, - anchorStateRegistry: anchorStateRegistry, - l2ChainId: 10 - }) - ) - ) - ) - }) - ); - - // Register the game implementation with the factory. - disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); + (address _impl, AlphabetVM _vm,) = setupFaultDisputeGame(absolutePrestate); + gameImpl = IFaultDisputeGame(_impl); // Set the init bond for the given game type. initBond = disputeGameFactory.initBonds(GAME_TYPE); diff --git a/packages/contracts-bedrock/test/dispute/PermissionedDisputeGame.t.sol b/packages/contracts-bedrock/test/dispute/PermissionedDisputeGame.t.sol index c9c7e6cb33e28..4a1bece164db2 100644 --- a/packages/contracts-bedrock/test/dispute/PermissionedDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/dispute/PermissionedDisputeGame.t.sol @@ -4,19 +4,12 @@ pragma solidity ^0.8.15; // Testing import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; - -// Scripts -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; - // Libraries import "src/dispute/lib/Types.sol"; import "src/dispute/lib/Errors.sol"; // Interfaces -import { IPreimageOracle } from "interfaces/dispute/IBigStepper.sol"; -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; -import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { /// @dev The type of the game being tested. @@ -37,60 +30,20 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant); function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public { - if (isForkTest()) { - // Fund the proposer on this fork. - vm.deal(PROPOSER, 100 ether); - } else { - // Set the time to a realistic date. + // Set the time to a realistic date. + if (!isForkTest()) { vm.warp(1690906994); } + // Fund the proposer on this fork. + vm.deal(PROPOSER, 100 ether); + // Set the extra data for the game creation extraData = abi.encode(l2BlockNumber); - IPreimageOracle oracle = IPreimageOracle( - DeployUtils.create1({ - _name: "PreimageOracle", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 0))) - }) - ); - AlphabetVM _vm = new AlphabetVM(absolutePrestate, oracle); - - // Use a 7 day delayed WETH to simulate withdrawals. - IDelayedWETH _weth = IDelayedWETH( - DeployUtils.create1({ - _name: "DelayedWETH", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IDelayedWETH.__constructor__, (7 days))) - }) - ); + (address _impl, AlphabetVM _vm,) = setupPermissionedDisputeGame(absolutePrestate, PROPOSER, CHALLENGER); + gameImpl = IPermissionedDisputeGame(_impl); - // Deploy an implementation of the fault game - gameImpl = IPermissionedDisputeGame( - DeployUtils.create1({ - _name: "PermissionedDisputeGame", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IPermissionedDisputeGame.__constructor__, - ( - IFaultDisputeGame.GameConstructorParams({ - gameType: GAME_TYPE, - absolutePrestate: absolutePrestate, - maxGameDepth: 2 ** 3, - splitDepth: 2 ** 2, - clockExtension: Duration.wrap(3 hours), - maxClockDuration: Duration.wrap(3.5 days), - vm: _vm, - weth: _weth, - anchorStateRegistry: anchorStateRegistry, - l2ChainId: 0 - }), - PROPOSER, - CHALLENGER - ) - ) - ) - }) - ); // Register the game implementation with the factory. disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); diff --git a/packages/contracts-bedrock/test/dispute/SuperFaultDisputeGame.t.sol b/packages/contracts-bedrock/test/dispute/SuperFaultDisputeGame.t.sol index b47ddb45a1039..9f824f81c7f2f 100644 --- a/packages/contracts-bedrock/test/dispute/SuperFaultDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/dispute/SuperFaultDisputeGame.t.sol @@ -34,6 +34,9 @@ contract SuperFaultDisputeGame_Init is DisputeGameFactory_Init { /// @dev The type of the game being tested. GameType internal immutable GAME_TYPE = GameTypes.SUPER_CANNON; + /// @dev The initial bond for the game. + uint256 internal initBond; + /// @dev The implementation of the game. ISuperFaultDisputeGame internal gameImpl; /// @dev The `Clone` proxy of the game. @@ -56,47 +59,10 @@ contract SuperFaultDisputeGame_Init is DisputeGameFactory_Init { // Set the extra data for the game creation extraData = abi.encode(l2SequenceNumber); - // Set preimage oracle challenge period to something arbitrary (4 seconds) just so we can - // actually test the clock extensions later on. This is not a realistic value. - AlphabetVM _vm = new AlphabetVM( - absolutePrestate, - IPreimageOracle( - DeployUtils.create1({ - _name: "PreimageOracle", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 4))) - }) - ) - ); + (address _impl, AlphabetVM _vm,) = setupSuperFaultDisputeGame(absolutePrestate); + gameImpl = ISuperFaultDisputeGame(_impl); - // Deploy an implementation of the fault game - gameImpl = ISuperFaultDisputeGame( - DeployUtils.create1({ - _name: "SuperFaultDisputeGame", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - ISuperFaultDisputeGame.__constructor__, - ( - ISuperFaultDisputeGame.GameConstructorParams({ - gameType: GAME_TYPE, - absolutePrestate: absolutePrestate, - maxGameDepth: 2 ** 3, - splitDepth: 2 ** 2, - clockExtension: Duration.wrap(3 hours), - maxClockDuration: Duration.wrap(3.5 days), - vm: _vm, - weth: delayedWeth, - anchorStateRegistry: anchorStateRegistry, - l2ChainId: 0 - }) - ) - ) - ) - }) - ); - - // Register the game implementation with the factory. - disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); - uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE); + initBond = disputeGameFactory.initBonds(GAME_TYPE); vm.prank(superchainConfig.guardian()); anchorStateRegistry.setRespectedGameType(GAME_TYPE); @@ -108,7 +74,7 @@ contract SuperFaultDisputeGame_Init is DisputeGameFactory_Init { // Create a new game. gameProxy = ISuperFaultDisputeGame( - payable(address(disputeGameFactory.create{ value: bondAmount }(GAME_TYPE, rootClaim, extraData))) + payable(address(disputeGameFactory.create{ value: initBond }(GAME_TYPE, rootClaim, extraData))) ); // Check immutables @@ -463,7 +429,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { Claim claim = _dummyClaim(); vm.expectRevert(abi.encodeWithSelector(UnexpectedRootClaim.selector, claim)); gameProxy = ISuperFaultDisputeGame( - payable(address(disputeGameFactory.create(GAME_TYPE, claim, abi.encode(_blockNumber)))) + payable(address(disputeGameFactory.create{ value: initBond }(GAME_TYPE, claim, abi.encode(_blockNumber)))) ); } @@ -490,7 +456,9 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { function test_initialize_invalidRoot_reverts() public { Claim claim = Claim.wrap(keccak256("invalid")); vm.expectRevert(bytes4(keccak256("SuperFaultDisputeGameInvalidRootClaim()"))); - gameProxy = ISuperFaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, extraData)))); + gameProxy = ISuperFaultDisputeGame( + payable(address(disputeGameFactory.create{ value: initBond }(GAME_TYPE, claim, extraData))) + ); } /// @dev Tests that the game cannot be initialized with extra data of the incorrect length (must be 32 bytes) @@ -514,7 +482,9 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { Claim claim = _dummyClaim(); vm.expectRevert(abi.encodeWithSelector(BadExtraData.selector)); - gameProxy = ISuperFaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, _extraData)))); + gameProxy = ISuperFaultDisputeGame( + payable(address(disputeGameFactory.create{ value: initBond }(GAME_TYPE, claim, _extraData))) + ); } /// @dev Tests that the game is initialized with the correct data. @@ -532,7 +502,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { assertEq(parentIndex, type(uint32).max); assertEq(counteredBy, address(0)); assertEq(claimant, address(this)); - assertEq(bond, 0); + assertEq(bond, initBond); assertEq(claim.raw(), ROOT_CLAIM.raw()); assertEq(position.raw(), 1); assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp))).raw()); @@ -555,7 +525,9 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { // Creation should fail. vm.expectRevert(AnchorRootNotFound.selector); - gameProxy = ISuperFaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, _dummyClaim(), hex"")))); + gameProxy = ISuperFaultDisputeGame( + payable(address(disputeGameFactory.create{ value: initBond }(GAME_TYPE, _dummyClaim(), hex""))) + ); } /// @dev Tests that the game cannot be initialized twice. @@ -937,7 +909,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { assertEq(parentIndex, type(uint32).max); assertEq(counteredBy, address(0)); assertEq(claimant, address(this)); - assertEq(bond, 0); + assertEq(bond, initBond); assertEq(claim.raw(), ROOT_CLAIM.raw()); assertEq(position.raw(), 1); assertEq(clock.raw(), LibClock.wrap(Duration.wrap(0), Timestamp.wrap(uint64(block.timestamp - 5))).raw()); @@ -1444,7 +1416,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { // Ensure we bonded the correct amounts assertEq(address(this).balance, bal - totalBonded); assertEq(address(gameProxy).balance, 0); - assertEq(delayedWeth.balanceOf(address(gameProxy)), totalBonded); + assertEq(delayedWeth.balanceOf(address(gameProxy)), initBond + totalBonded); // Resolve all claims vm.warp(block.timestamp + 3 days + 12 hours); @@ -1470,12 +1442,12 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { gameProxy.claimCredit(address(this)); // Ensure that bonds were paid out correctly. - assertEq(address(this).balance, bal); + assertEq(address(this).balance, bal + initBond); assertEq(address(gameProxy).balance, 0); assertEq(delayedWeth.balanceOf(address(gameProxy)), 0); // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future. - assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0); + assertEq(disputeGameFactory.initBonds(GAME_TYPE), initBond); } /// @dev Static unit test asserting that resolve pays out bonds on step, output bisection, and execution trace @@ -1544,7 +1516,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { assertEq(address(this).balance, 1000 ether - thisBonded); assertEq(bob.balance, 1000 ether - bobBonded); assertEq(address(gameProxy).balance, 0); - assertEq(delayedWeth.balanceOf(address(gameProxy)), thisBonded + bobBonded); + assertEq(delayedWeth.balanceOf(address(gameProxy)), initBond + thisBonded + bobBonded); // Resolve all claims vm.warp(block.timestamp + 3 days + 12 hours); @@ -1577,13 +1549,13 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { gameProxy.claimCredit(bob); // Ensure that bonds were paid out correctly. - assertEq(address(this).balance, 1000 ether + bobBonded); + assertEq(address(this).balance, 1000 ether + initBond + bobBonded); assertEq(bob.balance, 1000 ether - bobBonded); assertEq(address(gameProxy).balance, 0); assertEq(delayedWeth.balanceOf(address(gameProxy)), 0); // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future. - assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0); + assertEq(disputeGameFactory.initBonds(GAME_TYPE), initBond); } /// @dev Static unit test asserting that resolve pays out bonds on moves to the leftmost actor @@ -1654,14 +1626,14 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { // Ensure that bonds were paid out correctly. uint256 aliceLosses = firstBond; uint256 charlieLosses = secondBond; - assertEq(address(this).balance, bal + aliceLosses, "incorrect this balance"); + assertEq(address(this).balance, bal + aliceLosses + initBond, "incorrect this balance"); assertEq(alice.balance, bal - aliceLosses + charlieLosses, "incorrect alice balance"); assertEq(bob.balance, bal, "incorrect bob balance"); assertEq(charlie.balance, bal - charlieLosses, "incorrect charlie balance"); assertEq(address(gameProxy).balance, 0); // Ensure that the init bond for the game is 0, in case we change it in the test suite in the future. - assertEq(disputeGameFactory.initBonds(GAME_TYPE), 0); + assertEq(disputeGameFactory.initBonds(GAME_TYPE), initBond); } /// @dev Static unit test asserting that the anchor state updates when the game resolves in @@ -1842,7 +1814,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { // Ensure the game proxy has 1 ether in it. assertEq(address(gameProxy).balance, 1 ether); // Ensure the game has a balance of reenterBond in the delayedWeth contract. - assertEq(delayedWeth.balanceOf(address(gameProxy)), reenterBond); + assertEq(delayedWeth.balanceOf(address(gameProxy)), initBond + reenterBond); // Resolve the claim at index 2 first so that index 1 can be resolved. gameProxy.resolveClaim(2, 0); @@ -1881,7 +1853,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { assertEq(reenter.numCalls(), 2); assertEq(address(reenter).balance, reenterBond); assertEq(address(gameProxy).balance, 1 ether); - assertEq(delayedWeth.balanceOf(address(gameProxy)), 0); + assertEq(delayedWeth.balanceOf(address(gameProxy)), initBond); vm.stopPrank(); } @@ -2070,7 +2042,7 @@ contract SuperFaultDisputeGame_Test is SuperFaultDisputeGame_Init { // the leaves in our output bisection test tree, at SPLIT_DEPTH = 2 ** 2 ISuperFaultDisputeGame game = ISuperFaultDisputeGame( address( - disputeGameFactory.create( + disputeGameFactory.create{ value: initBond }( GAME_TYPE, Claim.wrap(bytes32(uint256(0xFF))), abi.encode(uint256(validl2SequenceNumber)) ) ) diff --git a/packages/contracts-bedrock/test/dispute/SuperPermissionedDisputeGame.t.sol b/packages/contracts-bedrock/test/dispute/SuperPermissionedDisputeGame.t.sol index f5d321181017e..19cf1219389d8 100644 --- a/packages/contracts-bedrock/test/dispute/SuperPermissionedDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/dispute/SuperPermissionedDisputeGame.t.sol @@ -5,22 +5,16 @@ pragma solidity ^0.8.15; import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; -// Scripts -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; - // Libraries import "src/dispute/lib/Types.sol"; import "src/dispute/lib/Errors.sol"; // Interfaces -import { IPreimageOracle } from "interfaces/dispute/IBigStepper.sol"; -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; -import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; contract SuperPermissionedDisputeGame_Init is DisputeGameFactory_Init { /// @dev The type of the game being tested. - GameType internal immutable GAME_TYPE = GameTypes.SUPER_PERMISSIONED_CANNON; + GameType internal constant GAME_TYPE = GameType.wrap(5); /// @dev Mock proposer key address internal constant PROPOSER = address(0xfacade9); /// @dev Mock challenger key @@ -37,62 +31,19 @@ contract SuperPermissionedDisputeGame_Init is DisputeGameFactory_Init { event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant); function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public { - if (isForkTest()) { - // Fund the proposer on this fork. - vm.deal(PROPOSER, 100 ether); - } else { - // Set the time to a realistic date. + // Set the time to a realistic date. + if (!isForkTest()) { vm.warp(1690906994); } + // Fund the proposer. + vm.deal(PROPOSER, 100 ether); + // Set the extra data for the game creation extraData = abi.encode(l2BlockNumber); - IPreimageOracle oracle = IPreimageOracle( - DeployUtils.create1({ - _name: "PreimageOracle", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IPreimageOracle.__constructor__, (0, 0))) - }) - ); - AlphabetVM _vm = new AlphabetVM(absolutePrestate, oracle); - - // Use a 7 day delayed WETH to simulate withdrawals. - IDelayedWETH _weth = IDelayedWETH( - DeployUtils.create1({ - _name: "DelayedWETH", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IDelayedWETH.__constructor__, (7 days))) - }) - ); - - // Deploy an implementation of the fault game - gameImpl = IPermissionedDisputeGame( - DeployUtils.create1({ - _name: "SuperPermissionedDisputeGame", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IPermissionedDisputeGame.__constructor__, - ( - IFaultDisputeGame.GameConstructorParams({ - gameType: GAME_TYPE, - absolutePrestate: absolutePrestate, - maxGameDepth: 2 ** 3, - splitDepth: 2 ** 2, - clockExtension: Duration.wrap(3 hours), - maxClockDuration: Duration.wrap(3.5 days), - vm: _vm, - weth: _weth, - anchorStateRegistry: anchorStateRegistry, - l2ChainId: 0 - }), - PROPOSER, - CHALLENGER - ) - ) - ) - }) - ); - // Register the game implementation with the factory. - disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); + (address _impl, AlphabetVM _vm,) = setupSuperPermissionedDisputeGame(absolutePrestate, PROPOSER, CHALLENGER); + gameImpl = IPermissionedDisputeGame(_impl); // Create a new game. uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE); diff --git a/packages/contracts-bedrock/test/invariants/OptimismPortal2.t.sol b/packages/contracts-bedrock/test/invariants/OptimismPortal2.t.sol index 6933217101c4c..774818de56e1d 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismPortal2.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismPortal2.t.sol @@ -6,6 +6,7 @@ import { StdUtils } from "forge-std/Test.sol"; import { Vm } from "forge-std/Vm.sol"; import { CommonTest } from "test/setup/CommonTest.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; +import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; // Contracts import { ResourceMetering } from "src/L1/ResourceMetering.sol"; @@ -81,7 +82,7 @@ contract OptimismPortal2_Depositor is StdUtils, ResourceMetering { } } -contract OptimismPortal2_Invariant_Harness is CommonTest { +contract OptimismPortal2_Invariant_Harness is DisputeGameFactory_Init { // Reusable default values for a test withdrawal Types.WithdrawalTransaction _defaultTx; @@ -120,14 +121,15 @@ contract OptimismPortal2_Invariant_Harness is CommonTest { // Warp forward in time to ensure that the game is created after the retirement timestamp. vm.warp(anchorStateRegistry.retirementTimestamp() + 1); + setupFaultDisputeGame(Claim.wrap(bytes32(0))); + // Create a dispute game with the output root we've proposed. _proposedBlockNumber = 0xFF; - GameType respectedGameType = optimismPortal2.respectedGameType(); IFaultDisputeGame game = IFaultDisputeGame( payable( address( - disputeGameFactory.create{ value: disputeGameFactory.initBonds(respectedGameType) }( - respectedGameType, Claim.wrap(_outputRoot), abi.encode(_proposedBlockNumber) + disputeGameFactory.create{ value: disputeGameFactory.initBonds(optimismPortal2.respectedGameType()) }( + optimismPortal2.respectedGameType(), Claim.wrap(_outputRoot), abi.encode(_proposedBlockNumber) ) ) ) diff --git a/packages/contracts-bedrock/test/periphery/monitoring/DisputeMonitorHelper.t.sol b/packages/contracts-bedrock/test/periphery/monitoring/DisputeMonitorHelper.t.sol index 99ca7af5004c2..c18134fcbe431 100644 --- a/packages/contracts-bedrock/test/periphery/monitoring/DisputeMonitorHelper.t.sol +++ b/packages/contracts-bedrock/test/periphery/monitoring/DisputeMonitorHelper.t.sol @@ -2,23 +2,29 @@ pragma solidity 0.8.15; // Testing -import { CommonTest } from "test/setup/CommonTest.sol"; +import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; +import { _changeClaimStatus } from "test/dispute/FaultDisputeGame.t.sol"; // Contracts import { DisputeMonitorHelper } from "src/periphery/monitoring/DisputeMonitorHelper.sol"; -import { GameTypes, Claim } from "src/dispute/lib/Types.sol"; +import { GameTypes, Claim, VMStatuses } from "src/dispute/lib/Types.sol"; import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; -contract DisputeMonitorHelper_TestInit is CommonTest { +contract DisputeMonitorHelper_TestInit is DisputeGameFactory_Init { DisputeMonitorHelper helper; function setUp() public override { super.setUp(); + helper = new DisputeMonitorHelper(); // Skip everything for forked networks. Tests here involve carefully controlling the list // of games in the factory, which is not possible on forked networks. skipIfForkTest("DisputeMonitorHelper tests are not applicable to forked networks"); + + Claim absolutePrestate = _changeClaimStatus(Claim.wrap(keccak256(abi.encode(0))), VMStatuses.UNFINISHED); + + setupFaultDisputeGame(absolutePrestate); } /// @notice Helper to create a game with a specific timestamp.