diff --git a/.gitignore b/.gitignore index 73a2e81b4..afbd7e903 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,8 @@ deploy-config/getting-started.json # IDE /.idea/ +# Foundry +foundry.lock + # OS .DS_Store diff --git a/Makefile b/Makefile index 70534f68d..9fdfbdbe9 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ deps: clean-lib github.com/safe-global/safe-contracts@bf943f80fec5ac647159d26161446ac5d716a294 \ github.com/Vectorized/solady@502cc1ea718e6fa73b380635ee0868b0740595f0 \ github.com/base/nitro-validator@0f006d2075637dd9640e530c4a7065f5c8bb2132 \ - github.com/base/op-enclave@a2d5398f04c3a8e4df929d58ee638ba4a037bfec + github.com/base/op-enclave@a2d5398f04c3a8e4df929d58ee638ba4a037bfec \ + github.com/automata-network/aws-nitro-enclave-attestation@10fe7be8d9840490f5655e4b2a2aba3a95ec88c1 forge install --no-git \ github.com/ethereum-optimism/superchain-registry@84bce73573f130008d84bae6e924163bab589a11 @# openzeppelin-contracts-v5 and solady-v0.0.245 use the same orgs as their diff --git a/deploy-config/hardhat.json b/deploy-config/hardhat.json index 8a0a3d4eb..c1c6714ea 100644 --- a/deploy-config/hardhat.json +++ b/deploy-config/hardhat.json @@ -72,5 +72,15 @@ "gasPayingTokenName": "", "gasPayingTokenSymbol": "", "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" + "liquidityControllerOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", + "teeImageHash": "0x0000000000000000000000000000000000000000000000000000000000000001", + "multiproofConfigHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "multiproofGameType": 621, + "teeProposer": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", + "nitroEnclaveVerifier": "0x0000000000000000000000000000000000000000", + "multiproofGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000001", + "multiproofGenesisBlockNumber": 0, + "multiproofBlockInterval": 100, + "multiproofIntermediateBlockInterval": 10, + "multiproofProofThreshold": 1 } diff --git a/deploy-config/sepolia-no-nitro.json b/deploy-config/sepolia-no-nitro.json deleted file mode 100644 index a88b13521..000000000 --- a/deploy-config/sepolia-no-nitro.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "finalSystemOwner": "0x6e427c3212C0b63BE0C382F97715D49b011bFF33", - "teeImageHash": "0x0000000000000000000000000000000000000000000000000000000000000001", - "teeProposer": "0xb28E6890Cffa969dA9851c1BF1Ac34B76EbFEe98", - "gameType": "621", - "genesisOutputRoot": "0xbc273d5876d1858ecd5aaf4ce4eaf16c73f0187ca4271b774ed5da7d2254ba79", - "genesisBlockNumber": "37223829", - "configHash": "0x12e9c45f19f9817c6d4385fad29e7a70c355502cf0883e76a9a7e478a85d1360" -} diff --git a/deploy-config/sepolia-with-nitro.json b/deploy-config/sepolia-with-nitro.json deleted file mode 100644 index ee0ad04e7..000000000 --- a/deploy-config/sepolia-with-nitro.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "finalSystemOwner": "0x6e427c3212C0b63BE0C382F97715D49b011bFF33", - "teeImageHash": "0x692a590aa58825d31ccfa165913f0a915c02ca58607b0f787a149179d2b69ec1", - "teeProposer": "0xb28E6890Cffa969dA9851c1BF1Ac34B76EbFEe98", - "gameType": "621", - "genesisOutputRoot": "0xbc273d5876d1858ecd5aaf4ce4eaf16c73f0187ca4271b774ed5da7d2254ba79", - "genesisBlockNumber": "37223829", - "configHash": "0x12e9c45f19f9817c6d4385fad29e7a70c355502cf0883e76a9a7e478a85d1360" -} diff --git a/deploy-config/sepolia.json b/deploy-config/sepolia.json index f5d209036..9a85de7a2 100644 --- a/deploy-config/sepolia.json +++ b/deploy-config/sepolia.json @@ -64,5 +64,15 @@ "gasPayingTokenName": "", "gasPayingTokenSymbol": "", "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301" + "liquidityControllerOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", + "teeImageHash": "0x0000000000000000000000000000000000000000000000000000000000000001", + "multiproofConfigHash": "0x12e9c45f19f9817c6d4385fad29e7a70c355502cf0883e76a9a7e478a85d1360", + "multiproofGameType": 621, + "teeProposer": "0xb28E6890Cffa969dA9851c1BF1Ac34B76EbFEe98", + "nitroEnclaveVerifier": "0x0000000000000000000000000000000000000000", + "multiproofGenesisOutputRoot": "0xbc273d5876d1858ecd5aaf4ce4eaf16c73f0187ca4271b774ed5da7d2254ba79", + "multiproofGenesisBlockNumber": 37223829, + "multiproofBlockInterval": 100, + "multiproofIntermediateBlockInterval": 10, + "multiproofProofThreshold": 1 } diff --git a/deployments/11155111-dev-no-nitro.json b/deployments/11155111-dev-no-nitro.json new file mode 100644 index 000000000..f98679b2f --- /dev/null +++ b/deployments/11155111-dev-no-nitro.json @@ -0,0 +1 @@ +{"SystemConfigGlobal":"0xf8293c0f3a36A746B559a1a51870339B20F60945","TEEVerifier":"0x82453dA61B397EE366fB2129502de9c216480aB6","DisputeGameFactory":"0xfEa8Cb315F75d838b6c76ae336a9255f81df0D50","AnchorStateRegistry":"0x556BD554854504BE2F2023F6531D25eF6f6Fe77D","DelayedWETH":"0xb1FB7f05711d2270cD658448562A29E8c5C95E9E","AggregateVerifier":"0xeeF18F1640fa79f919799B5D629908909e715f97"} \ No newline at end of file diff --git a/scripts/deploy/Deploy.s.sol b/scripts/deploy/Deploy.s.sol index ab04b9c37..77d2ddd47 100644 --- a/scripts/deploy/Deploy.s.sol +++ b/scripts/deploy/Deploy.s.sol @@ -283,6 +283,14 @@ contract Deploy is Deployer { faultGameV2SplitDepth: cfg.faultGameV2SplitDepth(), faultGameV2ClockExtension: cfg.faultGameV2ClockExtension(), faultGameV2MaxClockDuration: cfg.faultGameV2MaxClockDuration(), + teeImageHash: cfg.teeImageHash(), + multiproofConfigHash: cfg.multiproofConfigHash(), + multiproofGameType: cfg.multiproofGameType(), + nitroEnclaveVerifier: cfg.nitroEnclaveVerifier(), + l2ChainID: cfg.l2ChainID(), + multiproofBlockInterval: cfg.multiproofBlockInterval(), + multiproofIntermediateBlockInterval: cfg.multiproofIntermediateBlockInterval(), + multiproofProofThreshold: cfg.multiproofProofThreshold(), protocolVersionsProxy: IProtocolVersions(artifacts.mustGetAddress("ProtocolVersionsProxy")), superchainConfigProxy: superchainConfigProxy, superchainProxyAdmin: superchainProxyAdmin, diff --git a/scripts/deploy/DeployConfig.s.sol b/scripts/deploy/DeployConfig.s.sol index c1d9694c7..085194225 100644 --- a/scripts/deploy/DeployConfig.s.sol +++ b/scripts/deploy/DeployConfig.s.sol @@ -93,6 +93,18 @@ contract DeployConfig is Script { uint256 public faultGameV2ClockExtension; uint256 public faultGameV2MaxClockDuration; + // Multiproof Configuration + bytes32 public teeImageHash; + bytes32 public multiproofConfigHash; + uint256 public multiproofGameType; + address public teeProposer; + address public nitroEnclaveVerifier; + bytes32 public multiproofGenesisOutputRoot; + uint256 public multiproofGenesisBlockNumber; + uint256 public multiproofBlockInterval; + uint256 public multiproofIntermediateBlockInterval; + uint256 public multiproofProofThreshold; + bool public useInterop; bool public useUpgradedFork; bytes32 public devFeatureBitmap; @@ -192,6 +204,16 @@ contract DeployConfig is Script { faultGameV2SplitDepth = _readOr(_json, "$.faultGameV2SplitDepth", 30); faultGameV2ClockExtension = _readOr(_json, "$.faultGameV2ClockExtension", 10800); faultGameV2MaxClockDuration = _readOr(_json, "$.faultGameV2MaxClockDuration", 302400); + teeImageHash = bytes32(_readOr(_json, "$.teeImageHash", 0)); + multiproofConfigHash = bytes32(_readOr(_json, "$.multiproofConfigHash", 0)); + multiproofGameType = _readOr(_json, "$.multiproofGameType", 621); + teeProposer = _readOr(_json, "$.teeProposer", finalSystemOwner); + nitroEnclaveVerifier = stdJson.readAddress(_json, "$.nitroEnclaveVerifier"); + multiproofGenesisOutputRoot = bytes32(_readOr(_json, "$.multiproofGenesisOutputRoot", uint256(1))); + multiproofGenesisBlockNumber = _readOr(_json, "$.multiproofGenesisBlockNumber", 0); + multiproofBlockInterval = _readOr(_json, "$.multiproofBlockInterval", 100); + multiproofIntermediateBlockInterval = _readOr(_json, "$.multiproofIntermediateBlockInterval", 10); + multiproofProofThreshold = _readOr(_json, "$.multiproofProofThreshold", 1); } function fork() public view returns (Fork fork_) { diff --git a/scripts/deploy/DeployImplementations.s.sol b/scripts/deploy/DeployImplementations.s.sol index c4a45f36c..a4676f0d2 100644 --- a/scripts/deploy/DeployImplementations.s.sol +++ b/scripts/deploy/DeployImplementations.s.sol @@ -44,12 +44,14 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { CertManager } from "lib/nitro-validator/src/CertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; -import { DeployDevWithNitro } from "../multiproof/DeployDevWithNitro.s.sol"; import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; +import { GameType } from "src/dispute/lib/Types.sol"; contract DeployImplementations is Script { struct Input { @@ -65,6 +67,15 @@ contract DeployImplementations is Script { uint256 faultGameV2SplitDepth; uint256 faultGameV2ClockExtension; uint256 faultGameV2MaxClockDuration; + // Multiproof parameters + bytes32 teeImageHash; + bytes32 multiproofConfigHash; + uint256 multiproofGameType; + address nitroEnclaveVerifier; + uint256 l2ChainID; + uint256 multiproofBlockInterval; + uint256 multiproofIntermediateBlockInterval; + uint256 multiproofProofThreshold; // Outputs from DeploySuperchain.s.sol. ISuperchainConfig superchainConfigProxy; IProtocolVersions protocolVersionsProxy; @@ -137,7 +148,6 @@ contract DeployImplementations is Script { deployAnchorStateRegistryImpl(_input, output_); deployFaultDisputeGameV2Impl(_input, output_); deployPermissionedDisputeGameV2Impl(_input, output_); - deploySystemConfigGlobalImpl(_input, output_); deployAggregateVerifierImpl(_input, output_); if (DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPTIMISM_PORTAL_INTEROP)) { deploySuperFaultDisputeGameImpl(_input, output_); @@ -479,7 +489,7 @@ contract DeployImplementations is Script { function deployDisputeGameFactoryImpl(Output memory _output) private { IDisputeGameFactory impl = IDisputeGameFactory( DeployUtils.createDeterministic({ - _name: "src/dispute/DisputeGameFactory.sol:DisputeGameFactory", + _name: "DisputeGameFactory", _args: DeployUtils.encodeConstructor(abi.encodeCall(IDisputeGameFactory.__constructor__, ())), _salt: _salt }) @@ -706,40 +716,36 @@ contract DeployImplementations is Script { _output.opcmStandardValidator = impl; } - function deploySystemConfigGlobalImpl(Input memory, Output memory _output) private { - address certManager = address(new CertManager()); - SystemConfigGlobal scgImpl = new SystemConfigGlobal(CertManager(certManager)); - - vm.label(address(scgImpl), "SystemConfigGlobalImpl"); - _output.systemConfigGlobalImpl = scgImpl; - } - - function deployAggregateVerifierImpl(Input memory, Output memory _output) private { - DeployDevWithNitro nitro = new DeployDevWithNitro(); - DeployDevWithNitro.DeployConfig memory cfg = nitro.loadConfig(); - + function deployAggregateVerifierImpl(Input memory _input, Output memory _output) private { address zkVerifier = address(new MockVerifier()); - address teeVerifierImpl = address(new TEEVerifier(_output.systemConfigGlobalImpl)); - IVerifier aggregateVerifierImpl = IVerifier( + address teeVerifierImpl; + { + SystemConfigGlobal scgImpl = new SystemConfigGlobal(INitroEnclaveVerifier(_input.nitroEnclaveVerifier)); + vm.label(address(scgImpl), "SystemConfigGlobalImpl"); + _output.systemConfigGlobalImpl = scgImpl; + teeVerifierImpl = address(new TEEVerifier(scgImpl)); + } + + _output.aggregateVerifierImpl = IVerifier( address( new AggregateVerifier( - cfg.gameType, + GameType.wrap(uint32(_input.multiproofGameType)), _output.anchorStateRegistryImpl, _output.delayedWETHImpl, IVerifier(teeVerifierImpl), IVerifier(zkVerifier), - cfg.teeImageHash, + _input.teeImageHash, bytes32(0), - cfg.configHash, - 8453, - 100, - 10 + _input.multiproofConfigHash, + _input.l2ChainID, + _input.multiproofBlockInterval, + _input.multiproofIntermediateBlockInterval, + _input.multiproofProofThreshold ) ) ); - vm.label(address(aggregateVerifierImpl), "AggregateVerifierImpl"); - _output.aggregateVerifierImpl = aggregateVerifierImpl; + vm.label(address(_output.aggregateVerifierImpl), "AggregateVerifierImpl"); } function assertValidInput(Input memory _input) private pure { diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index 081b8ba9c..04f5cc9e3 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -43,7 +43,7 @@ pragma solidity 0.8.15; * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | * | Signer registration | addDevSigner() | registerSigner() | * | Requires Nitro enclave | No | Yes | - * | Validates AWS cert chain | No | Yes | + * | Validates attestation (ZK) | No | Yes | * | PCR0 pre-registration | No | Yes | * | Attestation freshness | N/A | < 60 minutes | * @@ -52,10 +52,11 @@ pragma solidity 0.8.15; * ══════════════════════════════════════════════════════════════════════════════════ */ -import { CertManager } from "lib/nitro-validator/src/CertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { Script } from "forge-std/Script.sol"; -import { stdJson } from "forge-std/StdJson.sol"; import { console2 as console } from "forge-std/console2.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; @@ -63,6 +64,10 @@ import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; import { GameType, Hash } from "src/dispute/lib/Types.sol"; +import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol"; +import { Config } from "scripts/libraries/Config.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; @@ -78,29 +83,18 @@ import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; /// @notice Development deployment WITHOUT AWS Nitro attestation validation. /// @dev Uses DevSystemConfigGlobal which allows addDevSigner() to bypass attestation. contract DeployDevNoNitro is Script { - using stdJson for string; - /// @notice Constant from Optimism's Constants.sol - the storage slot for proxy admin. bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; uint256 public constant BLOCK_INTERVAL = 100; uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 10; + uint256 public constant PROOF_THRESHOLD = 1; uint256 public constant INIT_BOND = 0.001 ether; - /// @notice Config struct to reduce stack variables. - struct DeployConfig { - address owner; - bytes32 teeImageHash; - address teeProposer; - GameType gameType; - uint256 gameTypeRaw; - bytes32 genesisOutputRoot; - uint256 genesisBlockNumber; - bytes32 configHash; - } + DeployConfig public constant cfg = + DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); // Deployed addresses - address public certManager; address public systemConfigGlobalProxy; address public teeVerifier; address public disputeGameFactory; @@ -108,61 +102,44 @@ contract DeployDevNoNitro is Script { address public mockDelayedWETH; address public aggregateVerifier; + function setUp() public { + DeployUtils.etchLabelAndAllowCheatcodes({ _etchTo: address(cfg), _cname: "DeployConfig" }); + cfg.read(Config.deployConfigPath()); + } + function run() public { - DeployConfig memory cfg = _loadConfig(); + GameType gameType = GameType.wrap(uint32(cfg.multiproofGameType())); console.log("=== Deploying Dev Infrastructure (NO NITRO) ==="); console.log("Chain ID:", block.chainid); - console.log("Owner:", cfg.owner); - console.log("TEE Proposer:", cfg.teeProposer); - console.log("Game Type:", cfg.gameTypeRaw); + console.log("Owner:", cfg.finalSystemOwner()); + console.log("TEE Proposer:", cfg.teeProposer()); + console.log("Game Type:", cfg.multiproofGameType()); console.log(""); console.log("NOTE: Using DevSystemConfigGlobal - NO attestation required."); vm.startBroadcast(); - _deployTEEContracts(cfg.owner); - _registerProposer(cfg.teeProposer); - _deployInfrastructure(cfg); - _deployAggregateVerifier(cfg); + _deployTEEContracts(cfg.finalSystemOwner()); + _registerProposer(cfg.teeProposer()); + _deployInfrastructure(gameType); + _deployAggregateVerifier(gameType); vm.stopBroadcast(); - _printSummary(cfg.teeImageHash, cfg.gameTypeRaw, cfg.configHash); + _printSummary(); _writeOutput(); } - function _loadConfig() internal view returns (DeployConfig memory cfg) { - string memory configPath = vm.envOr("DEPLOY_CONFIG_PATH", string("deploy-config/sepolia-no-nitro.json")); - string memory config = vm.readFile(configPath); - - cfg.owner = config.readAddress(".finalSystemOwner"); - cfg.teeImageHash = config.readBytes32(".teeImageHash"); - cfg.teeProposer = config.readAddressOr(".teeProposer", cfg.owner); - cfg.gameTypeRaw = config.readUintOr(".gameType", 621); - cfg.gameType = GameType.wrap(uint32(cfg.gameTypeRaw)); - cfg.genesisOutputRoot = config.readBytes32Or(".genesisOutputRoot", bytes32(uint256(1))); - cfg.genesisBlockNumber = config.readUintOr(".genesisBlockNumber", 0); - cfg.configHash = config.readBytes32Or(".configHash", bytes32(0)); - } - function _deployTEEContracts(address owner) internal { - // 1. CertManager (not used in dev mode, but deployed for interface compatibility) - certManager = address(new CertManager()); - console.log("CertManager:", certManager); - - // 2. DevSystemConfigGlobal - allows addDevSigner() to bypass attestation - address scgImpl = address(new DevSystemConfigGlobal(CertManager(certManager))); + address scgImpl = address(new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0)))); systemConfigGlobalProxy = address( new TransparentUpgradeableProxy( - scgImpl, - address(0xdead), // Non-upgradeable for testing - abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + scgImpl, address(0xdead), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) ) ); console.log("DevSystemConfigGlobal:", systemConfigGlobalProxy); - // 3. TEEVerifier teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); console.log("TEEVerifier:", teeVerifier); } @@ -172,65 +149,64 @@ contract DeployDevNoNitro is Script { console.log("Registered TEE proposer:", teeProposer); } - function _deployInfrastructure(DeployConfig memory cfg) internal { - // 4. REAL DisputeGameFactory (behind proxy) + function _deployInfrastructure(GameType gameType) internal { address factoryImpl = address(new DisputeGameFactory()); - MinimalProxyAdmin proxyAdmin = new MinimalProxyAdmin(cfg.owner); + MinimalProxyAdmin proxyAdmin = new MinimalProxyAdmin(cfg.finalSystemOwner()); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(factoryImpl, address(proxyAdmin), ""); vm.store(address(proxy), PROXY_OWNER_ADDRESS, bytes32(uint256(uint160(address(proxyAdmin))))); - DisputeGameFactory(address(proxy)).initialize(cfg.owner); + DisputeGameFactory(address(proxy)).initialize(cfg.finalSystemOwner()); disputeGameFactory = address(proxy); console.log("DisputeGameFactory:", disputeGameFactory); - // 5. Mock AnchorStateRegistry MockAnchorStateRegistry asr = new MockAnchorStateRegistry(); mockAnchorRegistry = address(asr); - asr.initialize(disputeGameFactory, Hash.wrap(cfg.genesisOutputRoot), cfg.genesisBlockNumber, cfg.gameType); + asr.initialize( + disputeGameFactory, + Hash.wrap(cfg.multiproofGenesisOutputRoot()), + cfg.multiproofGenesisBlockNumber(), + gameType + ); console.log("AnchorStateRegistry (mock):", mockAnchorRegistry); } - function _deployAggregateVerifier(DeployConfig memory cfg) internal { - // 6. Mock ZK Verifier + function _deployAggregateVerifier(GameType gameType) internal { address zkVerifier = address(new MockVerifier()); console.log("MockVerifier (ZK):", zkVerifier); - // 6.5. Mock DelayedWETH for bond handling mockDelayedWETH = address(new MockDelayedWETH()); console.log("MockDelayedWETH:", mockDelayedWETH); - // 7. AggregateVerifier aggregateVerifier = address( new AggregateVerifier( - cfg.gameType, + gameType, IAnchorStateRegistry(mockAnchorRegistry), IDelayedWETH(payable(mockDelayedWETH)), IVerifier(teeVerifier), IVerifier(zkVerifier), - cfg.teeImageHash, - bytes32(0), // zkImageHash (unused) - cfg.configHash, - 8453, // l2ChainId (Base mainnet) + cfg.teeImageHash(), + bytes32(0), + cfg.multiproofConfigHash(), + 8453, BLOCK_INTERVAL, - INTERMEDIATE_BLOCK_INTERVAL + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD ) ); console.log("AggregateVerifier:", aggregateVerifier); - // 8. Register AggregateVerifier with the factory - DisputeGameFactory(disputeGameFactory).setImplementation(cfg.gameType, IDisputeGame(aggregateVerifier)); - DisputeGameFactory(disputeGameFactory).setInitBond(cfg.gameType, INIT_BOND); + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); console.log("Registered AggregateVerifier with factory"); } - function _printSummary(bytes32 teeImageHash, uint256 gameType, bytes32 configHash) internal view { + function _printSummary() internal view { console.log("\n========================================"); console.log(" DEV DEPLOYMENT COMPLETE (NO NITRO)"); console.log("========================================"); console.log("\nTEE Contracts:"); - console.log(" CertManager:", certManager); console.log(" DevSystemConfigGlobal:", systemConfigGlobalProxy); console.log(" TEEVerifier:", teeVerifier); console.log("\nInfrastructure:"); @@ -239,14 +215,14 @@ contract DeployDevNoNitro is Script { console.log(" DelayedWETH (mock):", mockDelayedWETH); console.log("\nGame:"); console.log(" AggregateVerifier:", aggregateVerifier); - console.log(" Game Type:", gameType); - console.log(" TEE Image Hash:", vm.toString(teeImageHash)); - console.log(" Config Hash:", vm.toString(configHash)); + console.log(" Game Type:", cfg.multiproofGameType()); + console.log(" TEE Image Hash:", vm.toString(cfg.teeImageHash())); + console.log(" Config Hash:", vm.toString(cfg.multiproofConfigHash())); console.log("========================================"); console.log("\n>>> NEXT STEP - Register dev signer (NO ATTESTATION NEEDED) <<<"); console.log("\ncast send", systemConfigGlobalProxy); console.log(' "addDevSigner(address,bytes32)" '); - console.log(" ", vm.toString(teeImageHash)); + console.log(" ", vm.toString(cfg.teeImageHash())); console.log(" --private-key --rpc-url "); console.log("\n========================================\n"); } @@ -254,9 +230,7 @@ contract DeployDevNoNitro is Script { function _writeOutput() internal { string memory outPath = string.concat("deployments/", vm.toString(block.chainid), "-dev-no-nitro.json"); string memory output = string.concat( - '{"CertManager":"', - vm.toString(certManager), - '","SystemConfigGlobal":"', + '{"SystemConfigGlobal":"', vm.toString(systemConfigGlobalProxy), '","TEEVerifier":"', vm.toString(teeVerifier), diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index a3d6dca59..875674ae3 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -10,8 +10,9 @@ pragma solidity 0.8.15; * ══════════════════════════════════════════════════════════════════════════════════ * * This script deploys infrastructure using the REAL SystemConfigGlobal, which - * REQUIRES valid AWS Nitro attestation for signer registration. You cannot use - * addDevSigner() - you must go through the full registerSigner() flow. + * REQUIRES a ZK proof of a valid AWS Nitro attestation for signer registration. + * You cannot use addDevSigner() - you must go through the full registerSigner() flow. + * A pre-deployed NitroEnclaveVerifier contract address must be provided in the config. * * USE THIS SCRIPT WHEN: * - Testing the full Nitro attestation flow end-to-end @@ -43,49 +44,18 @@ pragma solidity 0.8.15; * Note: The teeImageHash in deploy-config is keccak256(PCR0_RAW), not the raw bytes. * * ───────────────────────────────────────────────────────────────────────────────── - * STEP 2: Get fresh attestation from the enclave + * STEP 2: Generate ZK proof of the attestation and register the signer * ───────────────────────────────────────────────────────────────────────────────── * - * Query the Nitro enclave for a signed attestation document. This contains: - * - The enclave's public key (from which the signer address is derived) - * - PCR0 (image hash) - * - Timestamp - * - AWS certificate chain signature - * - * curl -s -X POST $ENCLAVE_URL \ - * -H "Content-Type: application/json" \ - * -d '{"jsonrpc":"2.0","method":"enclave_signerAttestation","id":1}' \ - * | jq -r '.result' - * - * IMPORTANT: The attestation is only valid for 60 minutes! You must complete - * Step 3 within that window. - * - * ───────────────────────────────────────────────────────────────────────────────── - * STEP 3: Register the signer using the attestation - OWNER OR MANAGER - * ───────────────────────────────────────────────────────────────────────────────── - * - * Option A: Use the register-signer tool from base/op-enclave - * - * go install github.com/base/op-enclave/tools/register-signer@latest - * - * register-signer \ - * -attestation $ATTESTATION_HEX \ - * -deployment deployments/-dev-with-nitro.json \ - * -rpc $RPC_URL \ - * -private-key $OWNER_OR_MANAGER_KEY - * - * Option B: Call the contract directly (requires parsing attestation into TBS + sig) - * - * # The attestation is a COSE Sign1 structure. You need to split it into: - * # - attestationTbs: The "to-be-signed" payload - * # - signature: The ECDSA signature over the payload - * # - * # See: https://github.com/base/op-enclave/tree/main/tools/register-signer + * Generate a Risc0 ZK proof of the Nitro attestation offchain, then call: * * cast send $SYSTEM_CONFIG_GLOBAL \ - * "registerSigner(bytes,bytes)" $ATTESTATION_TBS $SIGNATURE \ + * "registerSigner(bytes,bytes)" $ZK_OUTPUT $ZK_PROOF_BYTES \ * --private-key $OWNER_OR_MANAGER_KEY --rpc-url $RPC_URL * + * IMPORTANT: The attestation is only valid for 60 minutes! Generate the proof + * and submit the transaction within that window. + * * ───────────────────────────────────────────────────────────────────────────────── * VERIFICATION * ───────────────────────────────────────────────────────────────────────────────── @@ -107,7 +77,7 @@ pragma solidity 0.8.15; * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | * | Signer registration | addDevSigner() | registerSigner() | * | Requires Nitro enclave | No | Yes | - * | Validates AWS cert chain | No | Yes | + * | Validates attestation (ZK) | No | Yes | * | PCR0 pre-registration | No | Yes | * | Attestation freshness | N/A | < 60 minutes | * @@ -116,10 +86,11 @@ pragma solidity 0.8.15; * ══════════════════════════════════════════════════════════════════════════════════ */ -import { CertManager } from "lib/nitro-validator/src/CertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { Script } from "forge-std/Script.sol"; -import { stdJson } from "forge-std/StdJson.sol"; import { console2 as console } from "forge-std/console2.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; @@ -127,6 +98,10 @@ import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; import { GameType, Hash } from "src/dispute/lib/Types.sol"; +import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol"; +import { Config } from "scripts/libraries/Config.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; @@ -141,29 +116,18 @@ import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; /// @notice Development deployment WITH AWS Nitro attestation validation. /// @dev Uses real SystemConfigGlobal which requires registerSigner() with valid attestation. contract DeployDevWithNitro is Script { - using stdJson for string; - /// @notice Constant from Optimism's Constants.sol - the storage slot for proxy admin. bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; uint256 public constant BLOCK_INTERVAL = 100; uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 10; + uint256 public constant PROOF_THRESHOLD = 1; uint256 public constant INIT_BOND = 0.001 ether; - /// @notice Config struct to reduce stack variables. - struct DeployConfig { - address owner; - bytes32 teeImageHash; - address teeProposer; - GameType gameType; - uint256 gameTypeRaw; - bytes32 genesisOutputRoot; - uint256 genesisBlockNumber; - bytes32 configHash; - } + DeployConfig public constant cfg = + DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); // Deployed addresses - address public certManager; address public systemConfigGlobalProxy; address public teeVerifier; address public disputeGameFactory; @@ -171,61 +135,46 @@ contract DeployDevWithNitro is Script { address public mockDelayedWETH; address public aggregateVerifier; + function setUp() public { + DeployUtils.etchLabelAndAllowCheatcodes({ _etchTo: address(cfg), _cname: "DeployConfig" }); + cfg.read(Config.deployConfigPath()); + } + function run() public { - DeployConfig memory cfg = loadConfig(); + GameType gameType = GameType.wrap(uint32(cfg.multiproofGameType())); console.log("=== Deploying Dev Infrastructure (WITH NITRO) ==="); console.log("Chain ID:", block.chainid); - console.log("Owner:", cfg.owner); - console.log("TEE Proposer:", cfg.teeProposer); - console.log("Game Type:", cfg.gameTypeRaw); + console.log("Owner:", cfg.finalSystemOwner()); + console.log("TEE Proposer:", cfg.teeProposer()); + console.log("Game Type:", cfg.multiproofGameType()); console.log(""); - console.log("NOTE: Using REAL SystemConfigGlobal - attestation REQUIRED."); + console.log("NOTE: Using REAL SystemConfigGlobal - ZK attestation proof REQUIRED."); + console.log("NitroEnclaveVerifier:", cfg.nitroEnclaveVerifier()); vm.startBroadcast(); - _deployTEEContracts(cfg.owner); - _registerProposer(cfg.teeProposer); - _deployInfrastructure(cfg); - _deployAggregateVerifier(cfg); + _deployTEEContracts(cfg.finalSystemOwner(), cfg.nitroEnclaveVerifier()); + _registerProposer(cfg.teeProposer()); + _deployInfrastructure(gameType); + _deployAggregateVerifier(gameType); vm.stopBroadcast(); - _printSummary(cfg); + _printSummary(); _writeOutput(); } - function loadConfig() public view returns (DeployConfig memory cfg) { - string memory configPath = vm.envOr("DEPLOY_CONFIG_PATH", string("deploy-config/sepolia-with-nitro.json")); - string memory config = vm.readFile(configPath); - - cfg.owner = config.readAddress(".finalSystemOwner"); - cfg.teeImageHash = config.readBytes32(".teeImageHash"); - cfg.teeProposer = config.readAddressOr(".teeProposer", cfg.owner); - cfg.gameTypeRaw = config.readUintOr(".gameType", 621); - cfg.gameType = GameType.wrap(uint32(cfg.gameTypeRaw)); - cfg.genesisOutputRoot = config.readBytes32Or(".genesisOutputRoot", bytes32(uint256(1))); - cfg.genesisBlockNumber = config.readUintOr(".genesisBlockNumber", 0); - cfg.configHash = config.readBytes32Or(".configHash", bytes32(0)); - } - - function _deployTEEContracts(address owner) internal { - // 1. CertManager - validates AWS Nitro certificate chains - certManager = address(new CertManager()); - console.log("CertManager:", certManager); - - // 2. SystemConfigGlobal (REAL version) - requires attestation for signer registration - address scgImpl = address(new SystemConfigGlobal(CertManager(certManager))); + function _deployTEEContracts(address owner, address _nitroEnclaveVerifier) internal { + address scgImpl = address(new SystemConfigGlobal(INitroEnclaveVerifier(_nitroEnclaveVerifier))); + console.log("NitroEnclaveVerifier (external):", _nitroEnclaveVerifier); systemConfigGlobalProxy = address( new TransparentUpgradeableProxy( - scgImpl, - address(0xdead), // Non-upgradeable for testing - abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + scgImpl, address(0xdead), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) ) ); console.log("SystemConfigGlobal:", systemConfigGlobalProxy); - // 3. TEEVerifier teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); console.log("TEEVerifier:", teeVerifier); } @@ -235,65 +184,65 @@ contract DeployDevWithNitro is Script { console.log("Registered TEE proposer:", teeProposer); } - function _deployInfrastructure(DeployConfig memory cfg) internal { - // 4. REAL DisputeGameFactory (behind proxy) + function _deployInfrastructure(GameType gameType) internal { address factoryImpl = address(new DisputeGameFactory()); - MinimalProxyAdmin proxyAdmin = new MinimalProxyAdmin(cfg.owner); + MinimalProxyAdmin proxyAdmin = new MinimalProxyAdmin(cfg.finalSystemOwner()); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(factoryImpl, address(proxyAdmin), ""); vm.store(address(proxy), PROXY_OWNER_ADDRESS, bytes32(uint256(uint160(address(proxyAdmin))))); - DisputeGameFactory(address(proxy)).initialize(cfg.owner); + DisputeGameFactory(address(proxy)).initialize(cfg.finalSystemOwner()); disputeGameFactory = address(proxy); console.log("DisputeGameFactory:", disputeGameFactory); - // 5. Mock AnchorStateRegistry MockAnchorStateRegistry asr = new MockAnchorStateRegistry(); mockAnchorRegistry = address(asr); - asr.initialize(disputeGameFactory, Hash.wrap(cfg.genesisOutputRoot), cfg.genesisBlockNumber, cfg.gameType); + asr.initialize( + disputeGameFactory, + Hash.wrap(cfg.multiproofGenesisOutputRoot()), + cfg.multiproofGenesisBlockNumber(), + gameType + ); console.log("AnchorStateRegistry (mock):", mockAnchorRegistry); } - function _deployAggregateVerifier(DeployConfig memory cfg) internal { - // 6. Mock ZK Verifier + function _deployAggregateVerifier(GameType gameType) internal { address zkVerifier = address(new MockVerifier()); console.log("MockVerifier (ZK):", zkVerifier); - // 6.5. Mock DelayedWETH for bond handling mockDelayedWETH = address(new MockDelayedWETH()); console.log("MockDelayedWETH:", mockDelayedWETH); - // 7. AggregateVerifier aggregateVerifier = address( new AggregateVerifier( - cfg.gameType, + gameType, IAnchorStateRegistry(mockAnchorRegistry), IDelayedWETH(payable(mockDelayedWETH)), IVerifier(teeVerifier), IVerifier(zkVerifier), - cfg.teeImageHash, - bytes32(0), // zkImageHash (unused) - cfg.configHash, - 8453, // l2ChainId (Base mainnet) + cfg.teeImageHash(), + bytes32(0), + cfg.multiproofConfigHash(), + 8453, BLOCK_INTERVAL, - INTERMEDIATE_BLOCK_INTERVAL + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD ) ); console.log("AggregateVerifier:", aggregateVerifier); - // 8. Register AggregateVerifier with the factory - DisputeGameFactory(disputeGameFactory).setImplementation(cfg.gameType, IDisputeGame(aggregateVerifier)); - DisputeGameFactory(disputeGameFactory).setInitBond(cfg.gameType, INIT_BOND); + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); console.log("Registered AggregateVerifier with factory"); } - function _printSummary(DeployConfig memory cfg) internal view { + function _printSummary() internal view { console.log("\n========================================"); console.log(" DEV DEPLOYMENT COMPLETE (WITH NITRO)"); console.log("========================================"); console.log("\nTEE Contracts:"); - console.log(" CertManager:", certManager); + console.log(" NitroEnclaveVerifier (external):", cfg.nitroEnclaveVerifier()); console.log(" SystemConfigGlobal:", systemConfigGlobalProxy); console.log(" TEEVerifier:", teeVerifier); console.log("\nInfrastructure:"); @@ -302,21 +251,20 @@ contract DeployDevWithNitro is Script { console.log(" DelayedWETH (mock):", mockDelayedWETH); console.log("\nGame:"); console.log(" AggregateVerifier:", aggregateVerifier); - console.log(" Game Type:", cfg.gameTypeRaw); - console.log(" TEE Image Hash:", vm.toString(cfg.teeImageHash)); - console.log(" Config Hash:", vm.toString(cfg.configHash)); + console.log(" Game Type:", cfg.multiproofGameType()); + console.log(" TEE Image Hash:", vm.toString(cfg.teeImageHash())); + console.log(" Config Hash:", vm.toString(cfg.multiproofConfigHash())); console.log("========================================"); - console.log("\n>>> NEXT STEPS (ATTESTATION REQUIRED) <<<"); + console.log("\n>>> NEXT STEPS (ZK ATTESTATION PROOF REQUIRED) <<<"); console.log("\n1. Register the PCR0 (raw 48-byte enclave image hash):"); console.log(" cast send", systemConfigGlobalProxy); console.log(' "registerPCR0(bytes)" '); console.log(" --private-key --rpc-url "); - console.log("\n2. Get attestation from enclave (valid for 60 min):"); - console.log(' curl -X POST -H "Content-Type: application/json"'); - console.log(" -d '{\"jsonrpc\":\"2.0\",\"method\":\"enclave_signerAttestation\",\"id\":1}'"); - console.log("\n3. Register signer with attestation:"); - console.log(" go install github.com/base/op-enclave/tools/register-signer@latest"); - console.log(" register-signer -attestation -rpc -private-key "); + console.log("\n2. Generate a Risc0 ZK proof of the Nitro attestation offchain."); + console.log("\n3. Register signer with ZK proof:"); + console.log(" cast send", systemConfigGlobalProxy); + console.log(' "registerSigner(bytes,bytes)" '); + console.log(" --private-key --rpc-url "); console.log("\nSee the comments at the top of this file for full details."); console.log("========================================\n"); } @@ -324,9 +272,7 @@ contract DeployDevWithNitro is Script { function _writeOutput() internal { string memory outPath = string.concat("deployments/", vm.toString(block.chainid), "-dev-with-nitro.json"); string memory output = string.concat( - '{"CertManager":"', - vm.toString(certManager), - '","SystemConfigGlobal":"', + '{"SystemConfigGlobal":"', vm.toString(systemConfigGlobalProxy), '","TEEVerifier":"', vm.toString(teeVerifier), diff --git a/snapshots/abi/AggregateVerifier.json b/snapshots/abi/AggregateVerifier.json new file mode 100644 index 000000000..2a142bdd7 --- /dev/null +++ b/snapshots/abi/AggregateVerifier.json @@ -0,0 +1,1068 @@ +[ + { + "inputs": [ + { + "internalType": "GameType", + "name": "gameType_", + "type": "uint32" + }, + { + "internalType": "contract IAnchorStateRegistry", + "name": "anchorStateRegistry_", + "type": "address" + }, + { + "internalType": "contract IDelayedWETH", + "name": "delayedWETH", + "type": "address" + }, + { + "internalType": "contract IVerifier", + "name": "teeVerifier", + "type": "address" + }, + { + "internalType": "contract IVerifier", + "name": "zkVerifier", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "teeImageHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "zkImageHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "l2ChainId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intermediateBlockInterval", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "BLOCKHASH_WINDOW", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BLOCK_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CONFIG_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DELAYED_WETH", + "outputs": [ + { + "internalType": "contract IDelayedWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DISPUTE_GAME_FACTORY", + "outputs": [ + { + "internalType": "contract IDisputeGameFactory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "EIP2935_CONTRACT", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "EIP2935_WINDOW", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FAST_FINALIZATION_DELAY", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INTERMEDIATE_BLOCK_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_CHAIN_ID", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SLOW_FINALIZATION_DELAY", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TEE_IMAGE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TEE_VERIFIER", + "outputs": [ + { + "internalType": "contract IVerifier", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZK_IMAGE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZK_VERIFIER", + "outputs": [ + { + "internalType": "contract IVerifier", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "anchorStateRegistry", + "outputs": [ + { + "internalType": "contract IAnchorStateRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bondAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bondClaimed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bondRecipient", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bondUnlocked", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "gameIndex", + "type": "uint256" + } + ], + "name": "challenge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "claimCredit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeGame", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "counteredByGameAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "createdAt", + "outputs": [ + { + "internalType": "Timestamp", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "expectedResolution", + "outputs": [ + { + "internalType": "Timestamp", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "extraData", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gameCreator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "gameData", + "outputs": [ + { + "internalType": "GameType", + "name": "", + "type": "uint32" + }, + { + "internalType": "Claim", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gameOver", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gameType", + "outputs": [ + { + "internalType": "GameType", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "proof", + "type": "bytes" + } + ], + "name": "initializeWithInitData", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "intermediateOutputRoot", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "intermediateOutputRoots", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "intermediateOutputRootsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1Head", + "outputs": [ + { + "internalType": "Hash", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "l2SequenceNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "intermediateRootIndex", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "intermediateRootToProve", + "type": "bytes32" + } + ], + "name": "nullify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "parentIndex", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "resolve", + "outputs": [ + { + "internalType": "enum GameStatus", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "resolvedAt", + "outputs": [ + { + "internalType": "Timestamp", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rootClaim", + "outputs": [ + { + "internalType": "Claim", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "startingBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "startingOutputRoot", + "outputs": [ + { + "internalType": "Hash", + "name": "root", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "l2SequenceNumber", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "startingRootHash", + "outputs": [ + { + "internalType": "Hash", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "status", + "outputs": [ + { + "internalType": "enum GameStatus", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "teeProver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + } + ], + "name": "verifyProposalProof", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "wasRespectedGameTypeWhenCreated", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zkProver", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IDisputeGame", + "name": "game", + "type": "address" + } + ], + "name": "Challenged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "CreditClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "nullifier", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "intermediateRootIndex", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "intermediateRoot", + "type": "bytes32" + } + ], + "name": "Nullified", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "prover", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum AggregateVerifier.ProofType", + "name": "proofType", + "type": "uint8" + } + ], + "name": "Proved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum GameStatus", + "name": "status", + "type": "uint8" + } + ], + "name": "Resolved", + "type": "event" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum AggregateVerifier.ProofType", + "name": "proofType", + "type": "uint8" + } + ], + "name": "AlreadyProven", + "type": "error" + }, + { + "inputs": [], + "name": "BondRecipientEmpty", + "type": "error" + }, + { + "inputs": [], + "name": "BondTransferFailed", + "type": "error" + }, + { + "inputs": [], + "name": "ClaimAlreadyResolved", + "type": "error" + }, + { + "inputs": [], + "name": "CounteredByGameNotResolved", + "type": "error" + }, + { + "inputs": [], + "name": "GameNotFinalized", + "type": "error" + }, + { + "inputs": [], + "name": "GameNotInProgress", + "type": "error" + }, + { + "inputs": [], + "name": "GameNotOver", + "type": "error" + }, + { + "inputs": [], + "name": "GameNotResolved", + "type": "error" + }, + { + "inputs": [], + "name": "GameOver", + "type": "error" + }, + { + "inputs": [], + "name": "GamePaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "intermediateRoot", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "claim", + "type": "bytes32" + } + ], + "name": "IntermediateRootMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "IntermediateRootSameAsProposed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "blockInterval", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "intermediateBlockInterval", + "type": "uint256" + } + ], + "name": "InvalidBlockInterval", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidCounteredByGame", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidGame", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidIntermediateRootIndex", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidParentGame", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidProof", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidProofType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "claimed", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "L1OriginHashMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "l1OriginNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentBlock", + "type": "uint256" + } + ], + "name": "L1OriginInFuture", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "l1OriginNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentBlock", + "type": "uint256" + } + ], + "name": "L1OriginTooOld", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum AggregateVerifier.ProofType", + "name": "proofType", + "type": "uint8" + } + ], + "name": "MissingProof", + "type": "error" + }, + { + "inputs": [], + "name": "NoCreditToClaim", + "type": "error" + }, + { + "inputs": [], + "name": "NoProofProvided", + "type": "error" + }, + { + "inputs": [], + "name": "ParentGameNotResolved", + "type": "error" + }, + { + "inputs": [], + "name": "Reentrancy", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expectedBlockNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualBlockNumber", + "type": "uint256" + } + ], + "name": "UnexpectedBlockNumber", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/BalanceTracker.json b/snapshots/abi/BalanceTracker.json new file mode 100644 index 000000000..136ef890e --- /dev/null +++ b/snapshots/abi/BalanceTracker.json @@ -0,0 +1,194 @@ +[ + { + "inputs": [ + { + "internalType": "address payable", + "name": "profitWallet", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [], + "name": "MAX_SYSTEM_ADDRESS_COUNT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PROFIT_WALLET", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable[]", + "name": "systemAddresses_", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "targetBalances_", + "type": "uint256[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "processFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "systemAddresses", + "outputs": [ + { + "internalType": "address payable", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "targetBalances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "systemAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balanceNeeded", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balanceSent", + "type": "uint256" + } + ], + "name": "ProcessedFunds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ReceivedFunds", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "profitWallet", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balanceSent", + "type": "uint256" + } + ], + "name": "SentProfit", + "type": "event" + } +] \ No newline at end of file diff --git a/snapshots/abi/CBMulticall.json b/snapshots/abi/CBMulticall.json new file mode 100644 index 000000000..9ac8ef7f6 --- /dev/null +++ b/snapshots/abi/CBMulticall.json @@ -0,0 +1,485 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "returnData", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call3[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call3Value[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3Value", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call3[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregateDelegateCalls", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "blockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getBasefee", + "outputs": [ + { + "internalType": "uint256", + "name": "basefee", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "getBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getChainId", + "outputs": [ + { + "internalType": "uint256", + "name": "chainid", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockCoinbase", + "outputs": [ + { + "internalType": "address", + "name": "coinbase", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockGasLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "gaslimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "getEthBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryAggregate", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryBlockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "MustDelegateCall", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/DevSystemConfigGlobal.json b/snapshots/abi/DevSystemConfigGlobal.json new file mode 100644 index 000000000..a082b6f79 --- /dev/null +++ b/snapshots/abi/DevSystemConfigGlobal.json @@ -0,0 +1,458 @@ +[ + { + "inputs": [ + { + "internalType": "contract INitroEnclaveVerifier", + "name": "nitroVerifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "MAX_AGE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NITRO_VERIFIER", + "outputs": [ + { + "internalType": "contract INitroEnclaveVerifier", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "pcr0Hash", + "type": "bytes32" + } + ], + "name": "addDevSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pcr0", + "type": "bytes" + } + ], + "name": "deregisterPCR0", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "deregisterSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "initialManager", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isValidProposer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "isValidSigner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pcr0", + "type": "bytes" + } + ], + "name": "registerPCR0", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + } + ], + "name": "registerSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceManagement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "name": "setProposer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "signerPCR0", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "transferManagement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "validPCR0s", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousManager", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "ManagementTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0Hash", + "type": "bytes32" + } + ], + "name": "PCR0Deregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0Hash", + "type": "bytes32" + } + ], + "name": "PCR0Registered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "name": "ProposerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "SignerDeregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0", + "type": "bytes32" + } + ], + "name": "SignerRegistered", + "type": "event" + }, + { + "inputs": [], + "name": "AttestationTooOld", + "type": "error" + }, + { + "inputs": [], + "name": "AttestationVerificationFailed", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPCR0", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPublicKey", + "type": "error" + }, + { + "inputs": [], + "name": "PCR0NotFound", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/DisputeGameFactory.json b/snapshots/abi/DisputeGameFactory.json index 016224be1..54f34da5f 100644 --- a/snapshots/abi/DisputeGameFactory.json +++ b/snapshots/abi/DisputeGameFactory.json @@ -33,6 +33,40 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "GameType", + "name": "_gameType", + "type": "uint32" + }, + { + "internalType": "Claim", + "name": "_rootClaim", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_extraData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_initData", + "type": "bytes" + } + ], + "name": "createWithInitData", + "outputs": [ + { + "internalType": "contract IDisputeGame", + "name": "proxy_", + "type": "address" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { diff --git a/snapshots/abi/FeeDisburser.json b/snapshots/abi/FeeDisburser.json new file mode 100644 index 000000000..4dfa787a5 --- /dev/null +++ b/snapshots/abi/FeeDisburser.json @@ -0,0 +1,182 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "l1Wallet", + "type": "address" + }, + { + "internalType": "uint256", + "name": "feeDisbursementInterval", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [], + "name": "FEE_DISBURSEMENT_INTERVAL", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L1_WALLET", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "WITHDRAWAL_MIN_GAS", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "disburseFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastDisbursementTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "netFeeRevenue", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "disbursementTime", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "deprecated", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalFeesDisbursed", + "type": "uint256" + } + ], + "name": "FeesDisbursed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "FeesReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "NoFeesCollected", + "type": "event" + }, + { + "inputs": [], + "name": "FeeVaultMustWithdrawToFeeDisburser", + "type": "error" + }, + { + "inputs": [], + "name": "FeeVaultMustWithdrawToL2", + "type": "error" + }, + { + "inputs": [], + "name": "IntervalNotReached", + "type": "error" + }, + { + "inputs": [], + "name": "IntervalTooLow", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/MockSystemConfig.json b/snapshots/abi/MockSystemConfig.json new file mode 100644 index 000000000..b36dfe198 --- /dev/null +++ b/snapshots/abi/MockSystemConfig.json @@ -0,0 +1,33 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "guardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } +] \ No newline at end of file diff --git a/snapshots/abi/MockVerifier.json b/snapshots/abi/MockVerifier.json new file mode 100644 index 000000000..d36cb2b27 --- /dev/null +++ b/snapshots/abi/MockVerifier.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function" + } +] \ No newline at end of file diff --git a/snapshots/abi/OPSuccinctFaultDisputeGame.json b/snapshots/abi/OPSuccinctFaultDisputeGame.json index 9e60e0034..6eb3a95f1 100644 --- a/snapshots/abi/OPSuccinctFaultDisputeGame.json +++ b/snapshots/abi/OPSuccinctFaultDisputeGame.json @@ -318,6 +318,19 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "initializeWithInitData", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [], "name": "l1Head", diff --git a/snapshots/abi/Recovery.json b/snapshots/abi/Recovery.json new file mode 100644 index 000000000..32eda0212 --- /dev/null +++ b/snapshots/abi/Recovery.json @@ -0,0 +1,138 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "OWNER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "targets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "withdrawETH", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/SmartEscrow.json b/snapshots/abi/SmartEscrow.json new file mode 100644 index 000000000..06bdc5288 --- /dev/null +++ b/snapshots/abi/SmartEscrow.json @@ -0,0 +1,977 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "benefactor_", + "type": "address" + }, + { + "internalType": "address", + "name": "beneficiary_", + "type": "address" + }, + { + "internalType": "address", + "name": "benefactorOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "beneficiaryOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "escrowOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "start_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cliffStart_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "end_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "vestingPeriodSeconds_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "initialTokens_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "vestingEventTokens_", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "BENEFACTOR_OWNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BENEFICIARY_OWNER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "OP_TOKEN", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TERMINATOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "acceptDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "beginDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "benefactor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "beneficiary", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cancelDefaultAdminTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + } + ], + "name": "changeDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cliffStart", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "contractTerminated", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultAdminDelayIncreaseWait", + "outputs": [ + { + "internalType": "uint48", + "name": "", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "end", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "initialTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingDefaultAdminDelay", + "outputs": [ + { + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "releasable", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "release", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "released", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "resume", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rollbackDefaultAdminDelay", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "start", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "terminate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newBenefactor", + "type": "address" + } + ], + "name": "updateBenefactor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newBeneficiary", + "type": "address" + } + ], + "name": "updateBeneficiary", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "vestedAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vestingEventTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vestingPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawUnvestedTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldBenefactor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newBenefactor", + "type": "address" + } + ], + "name": "BenefactorUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldBeneficiary", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newBeneficiary", + "type": "address" + } + ], + "name": "BeneficiaryUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "ContractResumed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "ContractTerminated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminDelayChangeCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint48", + "name": "newDelay", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "effectSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminDelayChangeScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "DefaultAdminTransferCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "acceptSchedule", + "type": "uint48" + } + ], + "name": "DefaultAdminTransferScheduled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensReleased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "benefactor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensWithdrawn", + "type": "event" + }, + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint48", + "name": "schedule", + "type": "uint48" + } + ], + "name": "AccessControlEnforcedDefaultAdminDelay", + "type": "error" + }, + { + "inputs": [], + "name": "AccessControlEnforcedDefaultAdminRules", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "defaultAdmin", + "type": "address" + } + ], + "name": "AccessControlInvalidDefaultAdmin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "AddressIsZeroAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cliffStartTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTimestamp", + "type": "uint256" + } + ], + "name": "CliffStartTimeAfterEndTime", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "cliffStartTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + } + ], + "name": "CliffStartTimeInvalid", + "type": "error" + }, + { + "inputs": [], + "name": "ContractIsNotTerminated", + "type": "error" + }, + { + "inputs": [], + "name": "ContractIsTerminated", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "startTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTimestamp", + "type": "uint256" + } + ], + "name": "StartTimeAfterEndTime", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vestingPeriodSeconds", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "endTimestamp", + "type": "uint256" + } + ], + "name": "UnevenVestingPeriod", + "type": "error" + }, + { + "inputs": [], + "name": "VestingEventTokensIsZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "vestingPeriodSeconds", + "type": "uint256" + } + ], + "name": "VestingPeriodExceedsContractDuration", + "type": "error" + }, + { + "inputs": [], + "name": "VestingPeriodIsZeroSeconds", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/SuperchainConfig.json b/snapshots/abi/SuperchainConfig.json index 67e886503..cfc27101f 100644 --- a/snapshots/abi/SuperchainConfig.json +++ b/snapshots/abi/SuperchainConfig.json @@ -1,9 +1,46 @@ [ { - "inputs": [], + "inputs": [ + { + "internalType": "address", + "name": "_guardian", + "type": "address" + }, + { + "internalType": "address", + "name": "_incidentResponder", + "type": "address" + } + ], "stateMutability": "nonpayable", "type": "constructor" }, + { + "inputs": [], + "name": "GUARDIAN", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INCIDENT_RESPONDER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -51,28 +88,15 @@ }, { "inputs": [], - "name": "initVersion", + "name": "incidentResponder", "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "internalType": "address", - "name": "_guardian", + "name": "", "type": "address" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -223,38 +247,6 @@ "stateMutability": "view", "type": "function" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "enum SuperchainConfig.UpdateType", - "name": "updateType", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "ConfigUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -265,7 +257,7 @@ "type": "address" } ], - "name": "Paused", + "name": "PauseExtended", "type": "event" }, { @@ -278,7 +270,7 @@ "type": "address" } ], - "name": "PauseExtended", + "name": "Paused", "type": "event" }, { @@ -324,11 +316,6 @@ "name": "ProxyAdminOwnedBase_ProxyAdminNotFound", "type": "error" }, - { - "inputs": [], - "name": "ReinitializableBase_ZeroInitVersion", - "type": "error" - }, { "inputs": [ { @@ -355,5 +342,10 @@ "inputs": [], "name": "SuperchainConfig_OnlyGuardian", "type": "error" + }, + { + "inputs": [], + "name": "SuperchainConfig_OnlyGuardianOrIncidentResponder", + "type": "error" } ] \ No newline at end of file diff --git a/snapshots/abi/SystemConfigGlobal.json b/snapshots/abi/SystemConfigGlobal.json new file mode 100644 index 000000000..e2e1a3db9 --- /dev/null +++ b/snapshots/abi/SystemConfigGlobal.json @@ -0,0 +1,440 @@ +[ + { + "inputs": [ + { + "internalType": "contract INitroEnclaveVerifier", + "name": "nitroVerifier", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "MAX_AGE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NITRO_VERIFIER", + "outputs": [ + { + "internalType": "contract INitroEnclaveVerifier", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pcr0", + "type": "bytes" + } + ], + "name": "deregisterPCR0", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "deregisterSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + }, + { + "internalType": "address", + "name": "initialManager", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isValidProposer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "isValidSigner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "manager", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "pcr0", + "type": "bytes" + } + ], + "name": "registerPCR0", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + } + ], + "name": "registerSigner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceManagement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "name": "setProposer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "signerPCR0", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "transferManagement", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "validPCR0s", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousManager", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newManager", + "type": "address" + } + ], + "name": "ManagementTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0Hash", + "type": "bytes32" + } + ], + "name": "PCR0Deregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0Hash", + "type": "bytes32" + } + ], + "name": "PCR0Registered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "proposer", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "name": "ProposerSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "SignerDeregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "pcr0", + "type": "bytes32" + } + ], + "name": "SignerRegistered", + "type": "event" + }, + { + "inputs": [], + "name": "AttestationTooOld", + "type": "error" + }, + { + "inputs": [], + "name": "AttestationVerificationFailed", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPCR0", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPublicKey", + "type": "error" + }, + { + "inputs": [], + "name": "PCR0NotFound", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/abi/TEEVerifier.json b/snapshots/abi/TEEVerifier.json new file mode 100644 index 000000000..b1bccadb7 --- /dev/null +++ b/snapshots/abi/TEEVerifier.json @@ -0,0 +1,116 @@ +[ + { + "inputs": [ + { + "internalType": "contract SystemConfigGlobal", + "name": "systemConfigGlobal", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "SYSTEM_CONFIG_GLOBAL", + "outputs": [ + { + "internalType": "contract SystemConfigGlobal", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "imageId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "journal", + "type": "bytes32" + } + ], + "name": "verify", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "signerPCR0", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "claimedImageId", + "type": "bytes32" + } + ], + "name": "ImageIdMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidProofFormat", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "proposer", + "type": "address" + } + ], + "name": "InvalidProposer", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + } + ], + "name": "InvalidSigner", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index 61b6e4e87..08bc12a07 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -3,10 +3,6 @@ "initCodeHash": "0xacbae98cc7c0f7ecbf36dc44bbf7cb0a011e6e6b781e28b9dbf947e31482b30d", "sourceCodeHash": "0xdddaf874cd201558e34f0ed78db38a58d798188f974646b0cad8ce9910f99037" }, - "src/L1/DataAvailabilityChallenge.sol:DataAvailabilityChallenge:dispute": { - "initCodeHash": "0xacbae98cc7c0f7ecbf36dc44bbf7cb0a011e6e6b781e28b9dbf947e31482b30d", - "sourceCodeHash": "0xdddaf874cd201558e34f0ed78db38a58d798188f974646b0cad8ce9910f99037" - }, "src/L1/ETHLockbox.sol:ETHLockbox": { "initCodeHash": "0x65db3aa3c2e3221065752f66016fa02b66688a01cc5c3066533b27fe620619c8", "sourceCodeHash": "0x6c9d3e2dee44c234d59ab93b6564536dfd807f1c4a02a82d5393bc53cb15b8b7" @@ -131,18 +127,10 @@ "initCodeHash": "0xe492fe75e3c0a8a80ede7b50271263c42a2c7616a101861e892dba76f9771e34", "sourceCodeHash": "0xef9cf289b4bf63808b6822fc2c588fe516abbbfb90479553e7d54d43de344e50" }, - "src/L2/LiquidityController.sol:LiquidityController:dispute": { - "initCodeHash": "0xb41fb5ed5d60d9c0fcdc21e222567a48632544b99ef0a298735a56d15e06f327", - "sourceCodeHash": "0xef9cf289b4bf63808b6822fc2c588fe516abbbfb90479553e7d54d43de344e50" - }, "src/L2/NativeAssetLiquidity.sol:NativeAssetLiquidity": { "initCodeHash": "0x04b176e5d484e54173a5644c833117c5fd9f055dce8678be9ec4cf07c0f01f00", "sourceCodeHash": "0x79289174e875ead5a6290df9af1951d6c0ff0dc6809601e1c7a80110ceb8e945" }, - "src/L2/NativeAssetLiquidity.sol:NativeAssetLiquidity:dispute": { - "initCodeHash": "0x04b176e5d484e54173a5644c833117c5fd9f055dce8678be9ec4cf07c0f01f00", - "sourceCodeHash": "0x79289174e875ead5a6290df9af1951d6c0ff0dc6809601e1c7a80110ceb8e945" - }, "src/L2/OperatorFeeVault.sol:OperatorFeeVault": { "initCodeHash": "0x2ebab6af089a714df25888a4dea81dadcb1fb57146be84d2e079041a9396a810", "sourceCodeHash": "0xd6e94bc9df025855916aa4184d0bc739b0fbe786dfd037b99dbb51d0d3e46918" @@ -251,13 +239,29 @@ "initCodeHash": "0x3a82e248129d19764bb975bb79b48a982f077f33bb508480bf8d2ec1c0c9810d", "sourceCodeHash": "0x955bd0c9b47e43219865e4e92abf28d916c96de20cbdf2f94c8ab14d02083759" }, + "src/multiproof/AggregateVerifier.sol:AggregateVerifier": { + "initCodeHash": "0x6e30a9816642f1ea2887f16223868fcd04ac80c3a42a4583dfc611d8331f8674", + "sourceCodeHash": "0xb9786dc79b4b494d81905235f7bda044c5b1a98ad82416829f5f6948be1175cc" + }, + "src/multiproof/AggregateVerifier.sol:AggregateVerifier:dispute": { + "initCodeHash": "0xc59c62a455533735aa9337d2db88b255713bd4dde20d3345265ec2fafe62af70", + "sourceCodeHash": "0xb9786dc79b4b494d81905235f7bda044c5b1a98ad82416829f5f6948be1175cc" + }, "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal": { - "initCodeHash": "0x2d681a39e518379b6d2c013735ae25a9bcf6e939d597bde9e6126375b86fd294", - "sourceCodeHash": "0xf1ec5f9b79fa641ab6ad4c6a2ff6e8fb313df953f773a7c8923e911fa465ffb3" + "initCodeHash": "0x76da4f2a736d7a39a01720e5d900a85fcaa60ba0430fcacbb8ab367f55ba5411", + "sourceCodeHash": "0xa6261402efe0105e2a4f9369818bafb4e65515e51850b44d47504151e1c39d01" }, "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal:dispute": { - "initCodeHash": "0x73537cace710afd0dc4ea7c2e25687a29cee13843617f518a3edeb8e79cf324c", - "sourceCodeHash": "0xf1ec5f9b79fa641ab6ad4c6a2ff6e8fb313df953f773a7c8923e911fa465ffb3" + "initCodeHash": "0xfae3a71157f3c64a7bda037ec116bf6e7265099397d9bcad22c01cc1f029ed7d", + "sourceCodeHash": "0xa6261402efe0105e2a4f9369818bafb4e65515e51850b44d47504151e1c39d01" + }, + "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { + "initCodeHash": "0x78317d9088a26523d938ce0d88ed0134abc60292c0cdb3f8a6a9530638fd9e9a", + "sourceCodeHash": "0x08e6d340b025c5a6c5997ef6fb69e6c14444f9e473b2c5337d6c10b6c89c0b4f" + }, + "src/multiproof/tee/TEEVerifier.sol:TEEVerifier:dispute": { + "initCodeHash": "0x78317d9088a26523d938ce0d88ed0134abc60292c0cdb3f8a6a9530638fd9e9a", + "sourceCodeHash": "0x08e6d340b025c5a6c5997ef6fb69e6c14444f9e473b2c5337d6c10b6c89c0b4f" }, "src/revenue-share/FeeDisburser.sol:FeeDisburser": { "initCodeHash": "0x1278027e3756e2989e80c0a7b513e221a5fe0d3dbd9ded108375a29b2c1f3d57", @@ -279,10 +283,6 @@ "initCodeHash": "0x0ad1f0f33517132b06a225b51e6eac48904d4ad691e0045eb70244d811d0d99d", "sourceCodeHash": "0xd6683fe9be4019d34249ada5a4de3e597f1bd9cd473a89f6eff8f749a0b0e978" }, - "src/safe/SaferSafes.sol:SaferSafes:dispute": { - "initCodeHash": "0x6a58b3e2c2567d6f5f936d335e6ae0750fddc367d322a555e685376fad49d7ef", - "sourceCodeHash": "0xd6683fe9be4019d34249ada5a4de3e597f1bd9cd473a89f6eff8f749a0b0e978" - }, "src/universal/OptimismMintableERC20.sol:OptimismMintableERC20": { "initCodeHash": "0x3c85eed0d017dca8eda6396aa842ddc12492587b061e8c756a8d32c4610a9658", "sourceCodeHash": "0x7023665d461f173417d932b55010b8f6c34f2bbaf56cfe4e1b15862c08cbcaac" diff --git a/snapshots/storageLayout/AggregateVerifier.json b/snapshots/storageLayout/AggregateVerifier.json new file mode 100644 index 000000000..1045c4170 --- /dev/null +++ b/snapshots/storageLayout/AggregateVerifier.json @@ -0,0 +1,93 @@ +[ + { + "bytes": "8", + "label": "createdAt", + "offset": 0, + "slot": "0", + "type": "Timestamp" + }, + { + "bytes": "8", + "label": "resolvedAt", + "offset": 8, + "slot": "0", + "type": "Timestamp" + }, + { + "bytes": "1", + "label": "status", + "offset": 16, + "slot": "0", + "type": "enum GameStatus" + }, + { + "bytes": "1", + "label": "initialized", + "offset": 17, + "slot": "0", + "type": "bool" + }, + { + "bytes": "1", + "label": "wasRespectedGameTypeWhenCreated", + "offset": 18, + "slot": "0", + "type": "bool" + }, + { + "bytes": "64", + "label": "startingOutputRoot", + "offset": 0, + "slot": "1", + "type": "struct Proposal" + }, + { + "bytes": "20", + "label": "bondRecipient", + "offset": 0, + "slot": "3", + "type": "address" + }, + { + "bytes": "1", + "label": "bondUnlocked", + "offset": 20, + "slot": "3", + "type": "bool" + }, + { + "bytes": "1", + "label": "bondClaimed", + "offset": 21, + "slot": "3", + "type": "bool" + }, + { + "bytes": "32", + "label": "bondAmount", + "offset": 0, + "slot": "4", + "type": "uint256" + }, + { + "bytes": "20", + "label": "counteredByGameAddress", + "offset": 0, + "slot": "5", + "type": "address" + }, + { + "bytes": "32", + "label": "proofTypeToProver", + "offset": 0, + "slot": "6", + "type": "mapping(enum AggregateVerifier.ProofType => address)" + }, + { + "bytes": "8", + "label": "expectedResolution", + "offset": 0, + "slot": "7", + "type": "Timestamp" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/BalanceTracker.json b/snapshots/storageLayout/BalanceTracker.json new file mode 100644 index 000000000..2fb7cb0a1 --- /dev/null +++ b/snapshots/storageLayout/BalanceTracker.json @@ -0,0 +1,44 @@ +[ + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "bool" + }, + { + "bytes": "32", + "label": "_status", + "offset": 0, + "slot": "1", + "type": "uint256" + }, + { + "bytes": "1568", + "label": "__gap", + "offset": 0, + "slot": "2", + "type": "uint256[49]" + }, + { + "bytes": "32", + "label": "systemAddresses", + "offset": 0, + "slot": "51", + "type": "address payable[]" + }, + { + "bytes": "32", + "label": "targetBalances", + "offset": 0, + "slot": "52", + "type": "uint256[]" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/CBMulticall.json b/snapshots/storageLayout/CBMulticall.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/snapshots/storageLayout/CBMulticall.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/snapshots/storageLayout/DevSystemConfigGlobal.json b/snapshots/storageLayout/DevSystemConfigGlobal.json new file mode 100644 index 000000000..2bd347c54 --- /dev/null +++ b/snapshots/storageLayout/DevSystemConfigGlobal.json @@ -0,0 +1,65 @@ +[ + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "bool" + }, + { + "bytes": "1600", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "uint256[50]" + }, + { + "bytes": "20", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "address" + }, + { + "bytes": "20", + "label": "_manager", + "offset": 0, + "slot": "52", + "type": "address" + }, + { + "bytes": "1536", + "label": "__gap", + "offset": 0, + "slot": "53", + "type": "uint256[48]" + }, + { + "bytes": "32", + "label": "validPCR0s", + "offset": 0, + "slot": "101", + "type": "mapping(bytes32 => bool)" + }, + { + "bytes": "32", + "label": "signerPCR0", + "offset": 0, + "slot": "102", + "type": "mapping(address => bytes32)" + }, + { + "bytes": "32", + "label": "isValidProposer", + "offset": 0, + "slot": "103", + "type": "mapping(address => bool)" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/FeeDisburser.json b/snapshots/storageLayout/FeeDisburser.json new file mode 100644 index 000000000..53ffb02a4 --- /dev/null +++ b/snapshots/storageLayout/FeeDisburser.json @@ -0,0 +1,16 @@ +[ + { + "bytes": "32", + "label": "lastDisbursementTime", + "offset": 0, + "slot": "0", + "type": "uint256" + }, + { + "bytes": "32", + "label": "netFeeRevenue", + "offset": 0, + "slot": "1", + "type": "uint256" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/MockSystemConfig.json b/snapshots/storageLayout/MockSystemConfig.json new file mode 100644 index 000000000..8ef57702b --- /dev/null +++ b/snapshots/storageLayout/MockSystemConfig.json @@ -0,0 +1,9 @@ +[ + { + "bytes": "20", + "label": "guardian", + "offset": 0, + "slot": "0", + "type": "address" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/MockVerifier.json b/snapshots/storageLayout/MockVerifier.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/snapshots/storageLayout/MockVerifier.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/snapshots/storageLayout/Recovery.json b/snapshots/storageLayout/Recovery.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/snapshots/storageLayout/Recovery.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/snapshots/storageLayout/SmartEscrow.json b/snapshots/storageLayout/SmartEscrow.json new file mode 100644 index 000000000..1b1333a15 --- /dev/null +++ b/snapshots/storageLayout/SmartEscrow.json @@ -0,0 +1,79 @@ +[ + { + "bytes": "32", + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "mapping(bytes32 => struct AccessControl.RoleData)" + }, + { + "bytes": "20", + "label": "_pendingDefaultAdmin", + "offset": 0, + "slot": "1", + "type": "address" + }, + { + "bytes": "6", + "label": "_pendingDefaultAdminSchedule", + "offset": 20, + "slot": "1", + "type": "uint48" + }, + { + "bytes": "6", + "label": "_currentDelay", + "offset": 26, + "slot": "1", + "type": "uint48" + }, + { + "bytes": "20", + "label": "_currentDefaultAdmin", + "offset": 0, + "slot": "2", + "type": "address" + }, + { + "bytes": "6", + "label": "_pendingDelay", + "offset": 20, + "slot": "2", + "type": "uint48" + }, + { + "bytes": "6", + "label": "_pendingDelaySchedule", + "offset": 26, + "slot": "2", + "type": "uint48" + }, + { + "bytes": "20", + "label": "benefactor", + "offset": 0, + "slot": "3", + "type": "address" + }, + { + "bytes": "20", + "label": "beneficiary", + "offset": 0, + "slot": "4", + "type": "address" + }, + { + "bytes": "32", + "label": "released", + "offset": 0, + "slot": "5", + "type": "uint256" + }, + { + "bytes": "1", + "label": "contractTerminated", + "offset": 0, + "slot": "6", + "type": "bool" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/SuperchainConfig.json b/snapshots/storageLayout/SuperchainConfig.json index b0aae64a5..57708ae70 100644 --- a/snapshots/storageLayout/SuperchainConfig.json +++ b/snapshots/storageLayout/SuperchainConfig.json @@ -1,30 +1,9 @@ [ - { - "bytes": "1", - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "20", - "label": "guardian", - "offset": 2, - "slot": "0", - "type": "address" - }, { "bytes": "32", "label": "pauseTimestamps", "offset": 0, - "slot": "1", + "slot": "0", "type": "mapping(address => uint256)" } ] \ No newline at end of file diff --git a/snapshots/storageLayout/SystemConfigGlobal.json b/snapshots/storageLayout/SystemConfigGlobal.json new file mode 100644 index 000000000..2bd347c54 --- /dev/null +++ b/snapshots/storageLayout/SystemConfigGlobal.json @@ -0,0 +1,65 @@ +[ + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "bool" + }, + { + "bytes": "1600", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "uint256[50]" + }, + { + "bytes": "20", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "address" + }, + { + "bytes": "20", + "label": "_manager", + "offset": 0, + "slot": "52", + "type": "address" + }, + { + "bytes": "1536", + "label": "__gap", + "offset": 0, + "slot": "53", + "type": "uint256[48]" + }, + { + "bytes": "32", + "label": "validPCR0s", + "offset": 0, + "slot": "101", + "type": "mapping(bytes32 => bool)" + }, + { + "bytes": "32", + "label": "signerPCR0", + "offset": 0, + "slot": "102", + "type": "mapping(address => bytes32)" + }, + { + "bytes": "32", + "label": "isValidProposer", + "offset": 0, + "slot": "103", + "type": "mapping(address => bool)" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/TEEVerifier.json b/snapshots/storageLayout/TEEVerifier.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/snapshots/storageLayout/TEEVerifier.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/multiproof/AggregateVerifier.sol b/src/multiproof/AggregateVerifier.sol index 5d8684481..21d255d48 100644 --- a/src/multiproof/AggregateVerifier.sol +++ b/src/multiproof/AggregateVerifier.sol @@ -24,8 +24,9 @@ import { FixedPointMathLib } from "@solady/utils/FixedPointMathLib.sol"; import { ReentrancyGuard } from "@solady/utils/ReentrancyGuard.sol"; import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; -contract AggregateVerifier is Clone, ReentrancyGuard { +contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { //////////////////////////////////////////////////////////////// // Enums // //////////////////////////////////////////////////////////////// @@ -56,6 +57,9 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @notice The maximum number of blocks that EIP-2935 can look back (~8192). uint256 public constant EIP2935_WINDOW = 8191; + /// @notice For when the game no longer accepts proofs and prevents resolution. + int8 internal constant NEGATIVE_PROOF_COUNT = type(int8).min; + //////////////////////////////////////////////////////////////// // Immutables // //////////////////////////////////////////////////////////////// @@ -100,6 +104,9 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @notice The game type ID. GameType internal immutable GAME_TYPE; + /// @notice The minimum number of proofs required to resolve the game. + uint256 public immutable PROOF_THRESHOLD; + //////////////////////////////////////////////////////////////// // State Vars // //////////////////////////////////////////////////////////////// @@ -143,6 +150,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @notice The timestamp of the game's expected resolution. Timestamp public expectedResolution; + /// @notice The number of proofs provided. + /// @dev Can be negative if a ZK proof is nullified. + int8 public proofCount; + //////////////////////////////////////////////////////////////// // Events // //////////////////////////////////////////////////////////////// @@ -238,6 +249,12 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @notice Thrown when the L1 origin hash doesn't match the actual blockhash. error L1OriginHashMismatch(bytes32 claimed, bytes32 actual); + /// @notice Thrown when there are not enough proofs to resolve the game. + error NotEnoughProofs(); + + /// @notice Thrown when the proof threshold is not positive. + error InvalidProofThreshold(); + /// @param gameType_ The game type. /// @param anchorStateRegistry_ The anchor state registry. /// @param delayedWETH The delayed WETH contract. @@ -248,6 +265,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @param configHash The hash of the rollup configuration. /// @param l2ChainId The chain ID of the L2 network. /// @param blockInterval The block interval. + /// @param intermediateBlockInterval The intermediate block interval. + /// @param proofThreshold The minimum number of proofs required to resolve the game. constructor( GameType gameType_, IAnchorStateRegistry anchorStateRegistry_, @@ -259,12 +278,17 @@ contract AggregateVerifier is Clone, ReentrancyGuard { bytes32 configHash, uint256 l2ChainId, uint256 blockInterval, - uint256 intermediateBlockInterval + uint256 intermediateBlockInterval, + uint256 proofThreshold ) { + // Block interval and intermediate block interval must be positive and divisible. if (blockInterval == 0 || intermediateBlockInterval == 0 || blockInterval % intermediateBlockInterval != 0) { revert InvalidBlockInterval(blockInterval, intermediateBlockInterval); } + // Proof threshold must be between 1 and 2. + if (proofThreshold != 1 && proofThreshold != 2) revert InvalidProofThreshold(); + // Set up initial game state. GAME_TYPE = gameType_; ANCHOR_STATE_REGISTRY = anchorStateRegistry_; @@ -278,6 +302,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard { L2_CHAIN_ID = l2ChainId; BLOCK_INTERVAL = blockInterval; INTERMEDIATE_BLOCK_INTERVAL = intermediateBlockInterval; + PROOF_THRESHOLD = proofThreshold; INITIALIZE_CALLDATA_SIZE = 0x7E + 0x20 * intermediateOutputRootsCount(); } @@ -436,6 +461,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard { status = GameStatus.DEFENDER_WINS; } + // casting to 'int256' is safe because 1 <= PROOF_THRESHOLD <= 2 + // forge-lint: disable-next-line(unsafe-typecast) + if (proofCount < int256(PROOF_THRESHOLD)) revert NotEnoughProofs(); + // Bond is refunded as no challenge was made or parent is invalid. bondRecipient = gameCreator(); // Mark the game as resolved. @@ -464,6 +493,9 @@ contract AggregateVerifier is Clone, ReentrancyGuard { if (proofTypeToProver[ProofType.TEE] == address(0)) revert MissingProof(ProofType.TEE); if (proofTypeToProver[ProofType.ZK] != address(0)) revert AlreadyProven(ProofType.ZK); + // Prevents challenging after TEE nullification. + if (proofCount != 1) revert NotEnoughProofs(); + (,, IDisputeGame game) = DISPUTE_GAME_FACTORY.gameAtIndex(gameIndex); // The game must be a valid game used to challenge. @@ -480,6 +512,12 @@ contract AggregateVerifier is Clone, ReentrancyGuard { // Set the game as challenged. status = GameStatus.CHALLENGER_WINS; + // Prevent resolution if any proof was somehow able to be provided later. + proofCount = NEGATIVE_PROOF_COUNT; + + // Update the expected resolution. + _updateExpectedResolution(); + // Set the bond recipient. // Bond cannot be claimed until the game used to challenge resolves as DEFENDER_WINS. bondRecipient = challengingGame.zkProver(); @@ -508,6 +546,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard { if (proposedIntermediateRoot == intermediateRootToProve) revert IntermediateRootSameAsProposed(); ProofType proofType = ProofType(uint8(proofBytes[0])); + if (proofTypeToProver[proofType] == address(0)) revert MissingProof(proofType); bytes32 startingRoot = intermediateRootIndex == 0 @@ -529,9 +568,30 @@ contract AggregateVerifier is Clone, ReentrancyGuard { abi.encodePacked(intermediateRootToProve) ); - // Set the game as challenged so that child games can't resolve. - status = GameStatus.CHALLENGER_WINS; - // Refund the bond. This can override a challenge. + if (proofType == ProofType.ZK) { + // Since a ZK proof vetoes a TEE proof, we make the proof count negative for ZK nullifications. + // This ensures that the game cannot resolve if a TEE proof can somehow be provided later. + proofCount = NEGATIVE_PROOF_COUNT; + + // Set the game as challenged so that child games can't resolve. + status = GameStatus.CHALLENGER_WINS; + } else if (proofType == ProofType.TEE) { + // The status is not updated here to still allow a ZK proof to be provided later. + proofCount -= 1; + + // Increase the expected resolution by the SLOW_FINALIZATION_DELAY. + // This gives us enough time to nullify a ZK proof if it was already provided. + // Otherwise the below _updateExpectedResolution() makes the expected resolution + // the maximum timestamp. + expectedResolution = Timestamp.wrap(uint64(block.timestamp + SLOW_FINALIZATION_DELAY)); + } + + // If there are no proofs, the expected resolution will be set to type(uint64).max. + // It's not possible to go from FAST_FINALIZATION_DELAY to SLOW_FINALIZATION_DELAY + // as we can only do a ZK nullification in this case, causing proofCount to be negative. + _updateExpectedResolution(); + + // Refund the bond as either a ZK proof was nullified or a ZK proof has to be provided later. bondRecipient = gameCreator(); emit Nullified(msg.sender, intermediateRootIndex, intermediateRootToProve); @@ -708,12 +768,18 @@ contract AggregateVerifier is Clone, ReentrancyGuard { /// @notice Updates the expected resolution timestamp. function _updateExpectedResolution() internal { - bool hasTee = proofTypeToProver[ProofType.TEE] != address(0); - bool hasZk = proofTypeToProver[ProofType.ZK] != address(0); + uint64 delay; - if (!hasTee && !hasZk) revert NoProofProvided(); + if (proofCount >= 2) { + delay = FAST_FINALIZATION_DELAY; + } else if (proofCount >= 1) { + delay = SLOW_FINALIZATION_DELAY; + } else { + // If there are no proofs, don't allow the game to resolve. + expectedResolution = Timestamp.wrap(type(uint64).max); + return; + } - uint64 delay = (hasTee && hasZk) ? FAST_FINALIZATION_DELAY : SLOW_FINALIZATION_DELAY; uint64 newResolution = uint64(block.timestamp) + delay; expectedResolution = Timestamp.wrap(uint64(FixedPointMathLib.min(newResolution, expectedResolution.raw()))); } @@ -726,6 +792,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard { bondRecipient = gameCreator(); } + proofCount += 1; + _updateExpectedResolution(); } @@ -773,7 +841,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard { } /// @notice Verifies a TEE proof for the current game. - /// @param proofBytes The proof: prover(20) + signature (65). + /// @param proofBytes The proof: signature(65). function _verifyTeeProof( bytes calldata proofBytes, address prover, @@ -914,4 +982,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard { revert L1OriginHashMismatch(l1OriginHash, actualHash); } } + + /// @notice Semantic version. + /// @custom:semver 0.1.0 + function version() public pure virtual returns (string memory) { + return "0.1.0"; + } } diff --git a/src/multiproof/mocks/MockCertManager.sol b/src/multiproof/mocks/MockCertManager.sol deleted file mode 100644 index f7e46c641..000000000 --- a/src/multiproof/mocks/MockCertManager.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; - -/// @title MockCertManager -/// @notice Mock CertManager for testing SystemConfigGlobal. -contract MockCertManager is ICertManager { - function verifyCACert(bytes memory, bytes32) external pure returns (bytes32) { - return bytes32(0); - } - - function verifyClientCert(bytes memory, bytes32) external pure returns (VerifiedCert memory) { - return VerifiedCert({ ca: false, notAfter: 0, maxPathLen: 0, subjectHash: bytes32(0), pubKey: "" }); - } -} diff --git a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol index 3f931be63..dfd61fa55 100644 --- a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol +++ b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; @@ -10,7 +12,7 @@ import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; /// @dev This contract adds addDevSigner() which bypasses AWS Nitro attestation verification. /// DO NOT deploy this contract to production networks. contract DevSystemConfigGlobal is SystemConfigGlobal { - constructor(ICertManager certManager) SystemConfigGlobal(certManager) { } + constructor(INitroEnclaveVerifier nitroVerifier) SystemConfigGlobal(nitroVerifier) { } /// @notice Registers a signer for testing (bypasses attestation verification). /// @dev Only callable by owner. For development/testing use only. diff --git a/src/multiproof/tee/SystemConfigGlobal.sol b/src/multiproof/tee/SystemConfigGlobal.sol index 0570ca3d1..3cce9895f 100644 --- a/src/multiproof/tee/SystemConfigGlobal.sol +++ b/src/multiproof/tee/SystemConfigGlobal.sol @@ -1,22 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { LibCborElement, CborElement, CborDecode } from "lib/nitro-validator/src/CborDecode.sol"; -import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; -import { LibBytes } from "lib/nitro-validator/src/LibBytes.sol"; -import { NitroValidator } from "lib/nitro-validator/src//NitroValidator.sol"; +import { + INitroEnclaveVerifier, + ZkCoProcessorType, + VerifierJournal, + VerificationResult, + Pcr, + Bytes48 +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { OwnableManagedUpgradeable } from "lib/op-enclave/contracts/src/OwnableManagedUpgradeable.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; /// @title SystemConfigGlobal -/// @notice Manages TEE signer registration via AWS Nitro attestation. -/// @dev Signers are registered by providing a valid AWS Nitro attestation document. +/// @notice Manages TEE signer registration via ZK-verified AWS Nitro attestation. +/// @dev Signers are registered by providing a ZK proof of a valid AWS Nitro attestation document, +/// verified through an external NitroEnclaveVerifier contract (Risc0). /// Each signer is associated with the PCR0 (enclave image hash) from their attestation, /// which allows TEEVerifier to validate that a signer was registered with a specific image. -contract SystemConfigGlobal is OwnableManagedUpgradeable, NitroValidator { - using LibBytes for bytes; - using CborDecode for bytes; - using LibCborElement for CborElement; - +contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { /// @notice Maximum age of an attestation document (60 minutes), in seconds. uint256 public constant MAX_AGE = 60 minutes; @@ -25,13 +27,15 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, NitroValidator { /// but block.timestamp is in seconds. uint256 private constant MS_PER_SECOND = 1000; + /// @notice The external NitroEnclaveVerifier contract used for ZK attestation verification. + INitroEnclaveVerifier public immutable NITRO_VERIFIER; + /// @notice Mapping of valid PCR0s (enclave image hashes) attested from AWS Nitro. /// @dev Only attestations with a PCR0 in this mapping can register signers. mapping(bytes32 => bool) public validPCR0s; /// @notice Mapping of signer address to the PCR0 they were registered with. /// @dev A non-zero value indicates the signer is valid and was registered with that PCR0. - /// This replaces the old validSigners(address => bool) mapping to enable imageId validation. mapping(address => bytes32) public signerPCR0; /// @notice Mapping of whether an address is a valid proposer. @@ -58,9 +62,17 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, NitroValidator { /// @notice Thrown when the attestation document is too old. error AttestationTooOld(); - constructor(ICertManager certManager) NitroValidator(certManager) { - // Always disable the implementation contract by setting dead addresses. - // Proxies will call initialize() to set the real owner/manager. + /// @notice Thrown when the ZK attestation verification fails. + error AttestationVerificationFailed(); + + /// @notice Thrown when PCR0 (index 0) is not found in the attestation's PCR list. + error PCR0NotFound(); + + /// @notice Thrown when the attestation's public key is too short to derive a signer address. + error InvalidPublicKey(); + + constructor(INitroEnclaveVerifier nitroVerifier) { + NITRO_VERIFIER = nitroVerifier; initialize({ initialOwner: address(0xdEaD), initialManager: address(0xdEaD) }); } @@ -88,27 +100,33 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, NitroValidator { emit PCR0Deregistered(pcr0Hash); } - /// @notice Registers a signer using an AWS Nitro attestation document. - /// @dev The attestation must: - /// 1. Be signed by a valid AWS Nitro certificate chain - /// 2. Contain a PCR0 that has been pre-registered via registerPCR0 - /// 3. Be less than MAX_AGE old - /// @param attestationTbs The TBS (to-be-signed) portion of the attestation document. - /// @param signature The signature over the attestation. - function registerSigner(bytes calldata attestationTbs, bytes calldata signature) external onlyOwnerOrManager { - Ptrs memory ptrs = validateAttestation(attestationTbs, signature); - bytes32 pcr0Hash = attestationTbs.keccak(ptrs.pcrs[0]); + /// @notice Registers a signer using a ZK proof of an AWS Nitro attestation document. + /// @dev The ZK proof must verify a valid attestation that: + /// 1. Has a valid AWS Nitro certificate chain (verified offchain via ZK) + /// 2. Contains a PCR0 that has been pre-registered via registerPCR0 + /// 3. Is less than MAX_AGE old + /// @param output The ABI-encoded VerifierJournal from the ZK proof. + /// @param proofBytes The Risc0 ZK proof bytes. + function registerSigner(bytes calldata output, bytes calldata proofBytes) external onlyOwnerOrManager { + VerifierJournal memory journal = NITRO_VERIFIER.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + if (journal.result != VerificationResult.Success) revert AttestationVerificationFailed(); + + if (journal.timestamp / MS_PER_SECOND + MAX_AGE <= block.timestamp) revert AttestationTooOld(); + + bytes32 pcr0Hash = _extractPCR0Hash(journal.pcrs); if (!validPCR0s[pcr0Hash]) revert InvalidPCR0(); - // Convert attestation timestamp from milliseconds to seconds before comparing - if (ptrs.timestamp / MS_PER_SECOND + MAX_AGE <= block.timestamp) revert AttestationTooOld(); - // The publicKey is encoded in the form specified in section 4.3.6 of ANSI X9.62, - // which is a 0x04 byte followed by the x and y coordinates of the public key. - // We ignore the first byte when hashing. - bytes32 publicKeyHash = attestationTbs.keccak(ptrs.publicKey.start() + 1, ptrs.publicKey.length() - 1); + // The publicKey is encoded in ANSI X9.62 format: 0x04 || x || y (65 bytes). + // We skip the first byte (0x04 prefix) when hashing to derive the address. + bytes memory pubKey = journal.publicKey; + if (pubKey.length != 65) revert InvalidPublicKey(); + bytes32 publicKeyHash; + assembly { + publicKeyHash := keccak256(add(pubKey, 0x21), sub(mload(pubKey), 1)) + } address enclaveAddress = address(uint160(uint256(publicKeyHash))); - // Store the PCR0 hash for this signer (enables imageId validation) signerPCR0[enclaveAddress] = pcr0Hash; emit SignerRegistered(enclaveAddress, pcr0Hash); } @@ -141,4 +159,15 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, NitroValidator { function version() public pure virtual returns (string memory) { return "0.1.0"; } + + /// @dev Finds PCR0 (index 0) in the PCR array and returns its keccak256 hash. + function _extractPCR0Hash(Pcr[] memory pcrs) internal pure returns (bytes32) { + for (uint256 i = 0; i < pcrs.length; i++) { + if (pcrs[i].index == 0) { + Bytes48 memory value = pcrs[i].value; + return keccak256(abi.encodePacked(value.first, value.second)); + } + } + revert PCR0NotFound(); + } } diff --git a/src/multiproof/tee/TEEVerifier.sol b/src/multiproof/tee/TEEVerifier.sol index c37857769..5bbf4e90c 100644 --- a/src/multiproof/tee/TEEVerifier.sol +++ b/src/multiproof/tee/TEEVerifier.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.15; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; import { SystemConfigGlobal } from "./SystemConfigGlobal.sol"; @@ -12,11 +13,9 @@ import { SystemConfigGlobal } from "./SystemConfigGlobal.sol"; /// @dev This contract is designed to be used as the TEE_VERIFIER in the AggregateVerifier. /// It verifies that proofs are signed by enclave addresses registered in SystemConfigGlobal /// via AWS Nitro attestation, and that the signer's PCR0 matches the claimed imageId. -/// Additionally, it verifies that the L1 origin block referenced in the proof actually exists -/// by checking against blockhash() or the EIP-2935 history contract. -/// The contract is intentionally stateless - all state related to output proposals is -/// managed by the calling contract (e.g., AggregateVerifier). -contract TEEVerifier is IVerifier { +/// The contract is intentionally stateless - all state related to output proposals and +/// L1 origin verification is managed by the calling contract (e.g., AggregateVerifier). +contract TEEVerifier is IVerifier, ISemver { /// @notice The SystemConfigGlobal contract that manages valid TEE signers. /// @dev Signers are registered via AWS Nitro attestation in SystemConfigGlobal. SystemConfigGlobal public immutable SYSTEM_CONFIG_GLOBAL; @@ -43,15 +42,15 @@ contract TEEVerifier is IVerifier { } /// @notice Verifies a TEE proof for a state transition. - /// @param proofBytes The proof: proposer (20) + l1OriginHash (32) + l1OriginNumber (32) + signature (65) = 149 - /// bytes. @param imageId The claimed TEE image hash (PCR0). Must match the signer's registered PCR0. + /// @param proofBytes The proof: proposer(20) + signature(65) = 85 bytes. + /// @param imageId The claimed TEE image hash (PCR0). Must match the signer's registered PCR0. /// @param journal The keccak256 hash of the proof's public inputs. /// @return valid Whether the proof is valid. function verify(bytes calldata proofBytes, bytes32 imageId, bytes32 journal) external view override returns (bool) { - if (proofBytes.length < 149) revert InvalidProofFormat(); + if (proofBytes.length < 85) revert InvalidProofFormat(); address proposer = address(bytes20(proofBytes[0:20])); - bytes calldata signature = proofBytes[84:149]; + bytes calldata signature = proofBytes[20:85]; // Recover the signer from the signature // The signature should be over the journal hash directly (not eth-signed-message prefixed) @@ -81,4 +80,10 @@ contract TEEVerifier is IVerifier { return true; } + + /// @notice Semantic version. + /// @custom:semver 0.1.0 + function version() public pure virtual returns (string memory) { + return "0.1.0"; + } } diff --git a/test/multiproof/AggregateVerifier.t.sol b/test/multiproof/AggregateVerifier.t.sol index 8a6666951..d7d00dff1 100644 --- a/test/multiproof/AggregateVerifier.t.sol +++ b/test/multiproof/AggregateVerifier.t.sol @@ -37,6 +37,7 @@ contract AggregateVerifierTest is BaseTest { assertEq(game.bondRecipient(), address(0)); assertEq(anchorStateRegistry.isGameProper(IDisputeGame(address(game))), true); assertEq(delayedWETH.balanceOf(address(game)), INIT_BOND); + assertEq(game.proofCount(), 1); } function testInitializeWithZKProof() public { @@ -62,6 +63,7 @@ contract AggregateVerifierTest is BaseTest { assertEq(game.bondRecipient(), ZK_PROVER); assertEq(anchorStateRegistry.isGameProper(IDisputeGame(address(game))), true); assertEq(delayedWETH.balanceOf(address(game)), INIT_BOND); + assertEq(game.proofCount(), 1); } function testInitializeFailsIfInvalidCallDataSize() public { @@ -149,6 +151,7 @@ contract AggregateVerifierTest is BaseTest { _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, teeProof); _provideProof(game, ZK_PROVER, zkProof); + assertEq(game.proofCount(), 2); // Unlock bond uint256 balanceBefore = game.gameCreator().balance; @@ -326,7 +329,8 @@ contract AggregateVerifierTest is BaseTest { CONFIG_HASH, L2_CHAIN_ID, 0, - INTERMEDIATE_BLOCK_INTERVAL + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD ); // Case 2: INTERMEDIATE_BLOCK_INTERVAL is 0 @@ -342,7 +346,8 @@ contract AggregateVerifierTest is BaseTest { CONFIG_HASH, L2_CHAIN_ID, BLOCK_INTERVAL, - 0 + 0, + PROOF_THRESHOLD ); // Case 3: BLOCK_INTERVAL is not divisible by INTERMEDIATE_BLOCK_INTERVAL @@ -358,7 +363,44 @@ contract AggregateVerifierTest is BaseTest { CONFIG_HASH, L2_CHAIN_ID, 3, - 2 + 2, + PROOF_THRESHOLD + ); + } + + function testDeployWithInvalidProofThreshold() public { + // Case 1: PROOF_THRESHOLD is 0 + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.InvalidProofThreshold.selector)); + new AggregateVerifier( + AGGREGATE_VERIFIER_GAME_TYPE, + IAnchorStateRegistry(address(anchorStateRegistry)), + IDelayedWETH(payable(address(delayedWETH))), + IVerifier(address(teeVerifier)), + IVerifier(address(zkVerifier)), + TEE_IMAGE_HASH, + ZK_IMAGE_HASH, + CONFIG_HASH, + L2_CHAIN_ID, + BLOCK_INTERVAL, + INTERMEDIATE_BLOCK_INTERVAL, + 0 + ); + + // Case 2: PROOF_THRESHOLD is > 2 + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.InvalidProofThreshold.selector)); + new AggregateVerifier( + AGGREGATE_VERIFIER_GAME_TYPE, + IAnchorStateRegistry(address(anchorStateRegistry)), + IDelayedWETH(payable(address(delayedWETH))), + IVerifier(address(teeVerifier)), + IVerifier(address(zkVerifier)), + TEE_IMAGE_HASH, + ZK_IMAGE_HASH, + CONFIG_HASH, + L2_CHAIN_ID, + BLOCK_INTERVAL, + INTERMEDIATE_BLOCK_INTERVAL, + 3 ); } } diff --git a/test/multiproof/BaseTest.t.sol b/test/multiproof/BaseTest.t.sol index e71727221..69cd7dd72 100644 --- a/test/multiproof/BaseTest.t.sol +++ b/test/multiproof/BaseTest.t.sol @@ -37,6 +37,7 @@ contract BaseTest is Test { uint256 public constant DELAYED_WETH_DELAY = 1 days; // Finality delay handled by the AggregateVerifier uint256 public constant FINALITY_DELAY = 0 days; + uint256 public constant PROOF_THRESHOLD = 1; uint256 public currentL2BlockNumber = 0; @@ -131,7 +132,8 @@ contract BaseTest is Test { CONFIG_HASH, L2_CHAIN_ID, BLOCK_INTERVAL, - INTERMEDIATE_BLOCK_INTERVAL + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD ); // Set the implementation for the aggregate verifier diff --git a/test/multiproof/Challenge.t.sol b/test/multiproof/Challenge.t.sol index 561cd3080..3d0ef2f65 100644 --- a/test/multiproof/Challenge.t.sol +++ b/test/multiproof/Challenge.t.sol @@ -38,6 +38,8 @@ contract ChallengeTest is BaseTest { assertEq(game1.bondRecipient(), ZK_PROVER); address counteredBy = game1.counteredByGameAddress(); assertEq(counteredBy, address(game2)); + assertEq(game1.proofCount(), -128); + assertEq(game1.expectedResolution().raw(), type(uint64).max); // Retrieve bond after challenge vm.warp(block.timestamp + 7 days); @@ -190,4 +192,43 @@ contract ChallengeTest is BaseTest { vm.expectRevert(AggregateVerifier.InvalidGame.selector); game.challenge(gameIndex); } + + function testChallengeFailsAfterTEENullification() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof1 = _generateProof("tee-proof-1", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof1); + + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee2"))); + bytes memory teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); + + game.nullify(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + + // challenge game + uint256 gameIndex = factory.gameCount() - 1; + vm.expectRevert(AggregateVerifier.NotEnoughProofs.selector); + game.challenge(gameIndex); + } + + function testChallengeFailsAfterZKNullification() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); + bytes memory zkProof1 = _generateProof("zk-proof-1", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, zkProof1); + + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk2"))); + bytes memory zkProof2 = _generateProof("zk-proof-2", AggregateVerifier.ProofType.ZK); + + game.nullify(zkProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + + // challenge game + uint256 gameIndex = factory.gameCount() - 1; + vm.expectRevert(ClaimAlreadyResolved.selector); + game.challenge(gameIndex); + } } diff --git a/test/multiproof/Nullify.t.sol b/test/multiproof/Nullify.t.sol index e7a360561..9ee51c066 100644 --- a/test/multiproof/Nullify.t.sol +++ b/test/multiproof/Nullify.t.sol @@ -23,8 +23,10 @@ contract NullifyTest is BaseTest { game.nullify(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); - assertEq(uint8(game.status()), uint8(GameStatus.CHALLENGER_WINS)); + assertEq(uint8(game.status()), uint8(GameStatus.IN_PROGRESS)); assertEq(game.bondRecipient(), TEE_PROVER); + assertEq(game.proofCount(), 0); + assertEq(game.expectedResolution().raw(), type(uint64).max); uint256 balanceBefore = game.gameCreator().balance; game.claimCredit(); @@ -50,6 +52,8 @@ contract NullifyTest is BaseTest { assertEq(uint8(game1.status()), uint8(GameStatus.CHALLENGER_WINS)); assertEq(game1.bondRecipient(), ZK_PROVER); + assertEq(game1.proofCount(), -128); + assertEq(game1.expectedResolution().raw(), type(uint64).max); uint256 balanceBefore = game1.gameCreator().balance; game1.claimCredit(); @@ -59,22 +63,28 @@ contract NullifyTest is BaseTest { assertEq(delayedWETH.balanceOf(address(game1)), 0); } - function testTEENullifyFailsIfNoTEEProof() public { + function testNullifyWithTEEProofWhenTEEAndZKProofsAreProvided() public { currentL2BlockNumber += BLOCK_INTERVAL; - Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); - bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof1 = _generateProof("tee-proof-1", AggregateVerifier.ProofType.TEE); - AggregateVerifier game1 = - _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, zkProof); + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof1); + + bytes memory zkProof = _generateProof("zk-proof-2", AggregateVerifier.ProofType.ZK); + game.verifyProposalProof(zkProof); + + assertEq(game.expectedResolution().raw(), block.timestamp + 1 days); Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee2"))); - bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + bytes memory teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); + game.nullify(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); - vm.expectRevert( - abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.TEE) - ); - game1.nullify(teeProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + assertEq(uint8(game.status()), uint8(GameStatus.IN_PROGRESS)); + assertEq(game.bondRecipient(), TEE_PROVER); + assertEq(game.proofCount(), 1); + assertEq(game.expectedResolution().raw(), block.timestamp + 7 days); } function testZKNullifyFailsIfNoZKProof() public { diff --git a/test/multiproof/SystemConfigGlobal.t.sol b/test/multiproof/SystemConfigGlobal.t.sol index d6b77961d..10636cbfa 100644 --- a/test/multiproof/SystemConfigGlobal.t.sol +++ b/test/multiproof/SystemConfigGlobal.t.sol @@ -6,24 +6,23 @@ import { Test } from "forge-std/Test.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; -import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { DevSystemConfigGlobal } from "src/multiproof/mocks/MockDevSystemConfigGlobal.sol"; import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; -import { MockCertManager } from "src/multiproof/mocks/MockCertManager.sol"; - /// @notice Tests for SystemConfigGlobal and DevSystemConfigGlobal contracts. /// @dev IMPORTANT: This test file uses DevSystemConfigGlobal as the implementation because -/// registering signers on the production SystemConfigGlobal requires valid AWS Nitro attestation -/// documents, which cannot be generated in a test environment. DevSystemConfigGlobal extends +/// registering signers on the production SystemConfigGlobal requires a ZK proof of a valid +/// AWS Nitro attestation, which cannot be generated in a test environment. DevSystemConfigGlobal extends /// SystemConfigGlobal with an `addDevSigner` function that bypasses attestation verification, /// allowing us to test all signer-related functionality. All tests for base SystemConfigGlobal /// functionality (PCR0 management, ownership, proposer, etc.) are equally valid since /// DevSystemConfigGlobal inherits from SystemConfigGlobal without modifying those functions. contract SystemConfigGlobalTest is Test { DevSystemConfigGlobal public systemConfigGlobal; - MockCertManager public certManager; ProxyAdmin public proxyAdmin; address public owner; @@ -48,11 +47,9 @@ contract SystemConfigGlobalTest is Test { pcr0Hash = keccak256(TEST_PCR0); - // Deploy mock cert manager - certManager = new MockCertManager(); - // Deploy implementation (using DevSystemConfigGlobal for test flexibility) - DevSystemConfigGlobal impl = new DevSystemConfigGlobal(ICertManager(address(certManager))); + // NitroEnclaveVerifier is not needed since tests use addDevSigner(), so pass address(0). + DevSystemConfigGlobal impl = new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0))); // Deploy proxy admin proxyAdmin = new ProxyAdmin(address(this)); diff --git a/test/multiproof/TEEVerifier.t.sol b/test/multiproof/TEEVerifier.t.sol index af3b91e09..3a1095d95 100644 --- a/test/multiproof/TEEVerifier.t.sol +++ b/test/multiproof/TEEVerifier.t.sol @@ -6,18 +6,17 @@ import { Test } from "forge-std/Test.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; -import { ICertManager } from "lib/nitro-validator/src/ICertManager.sol"; +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { DevSystemConfigGlobal } from "src/multiproof/mocks/MockDevSystemConfigGlobal.sol"; import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; -import { MockCertManager } from "src/multiproof/mocks/MockCertManager.sol"; - contract TEEVerifierTest is Test { TEEVerifier public verifier; DevSystemConfigGlobal public systemConfigGlobal; - MockCertManager public certManager; ProxyAdmin public proxyAdmin; // Test signer - we'll derive address from private key @@ -36,11 +35,8 @@ contract TEEVerifierTest is Test { // Derive signer address from private key signerAddress = vm.addr(SIGNER_PRIVATE_KEY); - // Deploy mock cert manager - certManager = new MockCertManager(); - - // Deploy implementation - DevSystemConfigGlobal impl = new DevSystemConfigGlobal(ICertManager(address(certManager))); + // Deploy implementation (NitroEnclaveVerifier not needed for dev signer tests) + DevSystemConfigGlobal impl = new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0))); // Deploy proxy admin proxyAdmin = new ProxyAdmin(address(this)); @@ -66,16 +62,12 @@ contract TEEVerifierTest is Test { // Create a journal hash bytes32 journal = keccak256("test-journal"); - // Get current block info for L1 origin - uint256 l1OriginNumber = block.number - 1; - bytes32 l1OriginHash = blockhash(l1OriginNumber); - // Sign the journal with the signer's private key (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_PRIVATE_KEY, journal); bytes memory signature = abi.encodePacked(r, s, v); - // Construct proof: proposer (20) + l1OriginHash (32) + l1OriginNumber (32) + signature (65) - bytes memory proofBytes = abi.encodePacked(PROPOSER, l1OriginHash, l1OriginNumber, signature); + // Construct proof: proposer(20) + signature(65) = 85 bytes + bytes memory proofBytes = abi.encodePacked(PROPOSER, signature); // Verify should return true bool result = verifier.verify(proofBytes, IMAGE_ID, journal); @@ -85,14 +77,11 @@ contract TEEVerifierTest is Test { function testVerifyFailsWithInvalidSignature() public { bytes32 journal = keccak256("test-journal"); - uint256 l1OriginNumber = block.number - 1; - bytes32 l1OriginHash = blockhash(l1OriginNumber); - // Create an invalid signature (all zeros except v) bytes memory invalidSignature = new bytes(65); invalidSignature[64] = bytes1(uint8(27)); // Set v to 27 - bytes memory proofBytes = abi.encodePacked(PROPOSER, l1OriginHash, l1OriginNumber, invalidSignature); + bytes memory proofBytes = abi.encodePacked(PROPOSER, invalidSignature); vm.expectRevert(TEEVerifier.InvalidSignature.selector); verifier.verify(proofBytes, IMAGE_ID, journal); @@ -102,16 +91,12 @@ contract TEEVerifierTest is Test { // Create a journal hash bytes32 journal = keccak256("test-journal"); - // Get current block info for L1 origin - uint256 l1OriginNumber = block.number - 1; - bytes32 l1OriginHash = blockhash(l1OriginNumber); - // Sign the journal with the signer's private key (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_PRIVATE_KEY, journal); bytes memory signature = abi.encodePacked(r, s, v); - // Construct proof: proposer (20) + l1OriginHash (32) + l1OriginNumber (32) + signature (65) - bytes memory proofBytes = abi.encodePacked(address(0), l1OriginHash, l1OriginNumber, signature); + // Construct proof: proposer(20) + signature(65) = 85 bytes + bytes memory proofBytes = abi.encodePacked(address(0), signature); vm.expectRevert(abi.encodeWithSelector(TEEVerifier.InvalidProposer.selector, address(0))); verifier.verify(proofBytes, IMAGE_ID, journal); @@ -124,13 +109,10 @@ contract TEEVerifierTest is Test { bytes32 journal = keccak256("test-journal"); - uint256 l1OriginNumber = block.number - 1; - bytes32 l1OriginHash = blockhash(l1OriginNumber); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(unregisteredKey, journal); bytes memory signature = abi.encodePacked(r, s, v); - bytes memory proofBytes = abi.encodePacked(PROPOSER, l1OriginHash, l1OriginNumber, signature); + bytes memory proofBytes = abi.encodePacked(PROPOSER, signature); vm.expectRevert(abi.encodeWithSelector(TEEVerifier.InvalidSigner.selector, unregisteredSigner)); verifier.verify(proofBytes, IMAGE_ID, journal); @@ -139,13 +121,10 @@ contract TEEVerifierTest is Test { function testVerifyFailsWithImageIdMismatch() public { bytes32 journal = keccak256("test-journal"); - uint256 l1OriginNumber = block.number - 1; - bytes32 l1OriginHash = blockhash(l1OriginNumber); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(SIGNER_PRIVATE_KEY, journal); bytes memory signature = abi.encodePacked(r, s, v); - bytes memory proofBytes = abi.encodePacked(PROPOSER, l1OriginHash, l1OriginNumber, signature); + bytes memory proofBytes = abi.encodePacked(PROPOSER, signature); // Use a different imageId that doesn't match the registered PCR0 bytes32 wrongImageId = keccak256("wrong-image-id"); @@ -157,8 +136,8 @@ contract TEEVerifierTest is Test { function testVerifyFailsWithInvalidProofFormat() public { bytes32 journal = keccak256("test-journal"); - // Proof too short (less than 129 bytes) - bytes memory shortProof = new bytes(100); + // Proof too short (less than 85 bytes) + bytes memory shortProof = new bytes(50); vm.expectRevert(TEEVerifier.InvalidProofFormat.selector); verifier.verify(shortProof, IMAGE_ID, journal); diff --git a/test/opcm/DeployImplementations.t.sol b/test/opcm/DeployImplementations.t.sol index 1a4f4162f..73315b82f 100644 --- a/test/opcm/DeployImplementations.t.sol +++ b/test/opcm/DeployImplementations.t.sol @@ -236,6 +236,14 @@ contract DeployImplementations_Test is Test, FeatureFlags { _faultGameV2SplitDepth, // faultGameV2SplitDepth (bounded) _faultGameV2ClockExtension, // faultGameV2ClockExtension (bounded) _faultGameV2MaxClockDuration, // faultGameV2MaxClockDuration (bounded) + bytes32(uint256(1)), // teeImageHash + bytes32(0), // multiproofConfigHash + 621, // multiproofGameType + address(0), // nitroEnclaveVerifier + 8453, // l2ChainID + 100, // multiproofBlockInterval + 10, // multiproofIntermediateBlockInterval + 1, // multiproofProofThreshold superchainConfigProxy, protocolVersionsProxy, superchainProxyAdmin, @@ -524,6 +532,14 @@ contract DeployImplementations_Test is Test, FeatureFlags { 30, // faultGameV2SplitDepth 10800, // faultGameV2ClockExtension 302400, // faultGameV2MaxClockDuration + bytes32(uint256(1)), // teeImageHash + bytes32(0), // multiproofConfigHash + 621, // multiproofGameType + address(0), // nitroEnclaveVerifier + 8453, // l2ChainID + 100, // multiproofBlockInterval + 10, // multiproofIntermediateBlockInterval + 1, // multiproofProofThreshold superchainConfigProxy, protocolVersionsProxy, superchainProxyAdmin, diff --git a/test/opcm/DeployOPChain.t.sol b/test/opcm/DeployOPChain.t.sol index c5f945822..b8520079c 100644 --- a/test/opcm/DeployOPChain.t.sol +++ b/test/opcm/DeployOPChain.t.sol @@ -94,6 +94,14 @@ contract DeployOPChain_TestBase is Test, FeatureFlags { faultGameV2SplitDepth: 30, faultGameV2ClockExtension: 10800, faultGameV2MaxClockDuration: 302400, + teeImageHash: bytes32(uint256(1)), + multiproofConfigHash: bytes32(0), + multiproofGameType: 621, + nitroEnclaveVerifier: address(0), + l2ChainID: 8453, + multiproofBlockInterval: 100, + multiproofIntermediateBlockInterval: 10, + multiproofProofThreshold: 1, superchainConfigProxy: dso.superchainConfigProxy, protocolVersionsProxy: dso.protocolVersionsProxy, superchainProxyAdmin: dso.superchainProxyAdmin, diff --git a/test/vendor/Initializable.t.sol b/test/vendor/Initializable.t.sol index e43ec8c22..306eb2628 100644 --- a/test/vendor/Initializable.t.sol +++ b/test/vendor/Initializable.t.sol @@ -22,6 +22,7 @@ import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol" import { ProtocolVersion } from "interfaces/L1/IProtocolVersions.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; +import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; /// @title Initializer_Test /// @dev Ensures that the `initialize()` function on contracts cannot be called more than @@ -338,34 +339,40 @@ contract Initializer_Test is CommonTest { }) ); - // ETHLockboxImpl - contracts.push( - InitializeableContract({ - name: "ETHLockboxImpl", - target: EIP1967Helper.getImplementation(address(ethLockbox)), - initCalldata: abi.encodeCall( - ethLockbox.initialize, (ISystemConfig(address(0)), new IOptimismPortal2[](0)) - ) - }) - ); + // ETHLockbox is only deployed when interop is enabled + if (address(ethLockbox) != address(0)) { + // ETHLockboxImpl + contracts.push( + InitializeableContract({ + name: "ETHLockboxImpl", + target: EIP1967Helper.getImplementation(address(ethLockbox)), + initCalldata: abi.encodeCall( + ethLockbox.initialize, (ISystemConfig(address(0)), new IOptimismPortal2[](0)) + ) + }) + ); - // ETHLockboxProxy - contracts.push( - InitializeableContract({ - name: "ETHLockboxProxy", - target: address(ethLockbox), - initCalldata: abi.encodeCall( - ethLockbox.initialize, (ISystemConfig(address(0)), new IOptimismPortal2[](0)) - ) - }) - ); + // ETHLockboxProxy + contracts.push( + InitializeableContract({ + name: "ETHLockboxProxy", + target: address(ethLockbox), + initCalldata: abi.encodeCall( + ethLockbox.initialize, (ISystemConfig(address(0)), new IOptimismPortal2[](0)) + ) + }) + ); + } + + // AggregateVerifier uses a custom `bool initialized` instead of OpenZeppelin's `_initialized` + // uint8, so it cannot be tested by this framework. It is excluded below. - // SystemConfigGlobal (Multiproof) + // SystemConfigGlobalImpl contracts.push( InitializeableContract({ name: "SystemConfigGlobalImpl", target: address(systemConfigGlobal), - initCalldata: abi.encodeCall(systemConfigGlobal.initialize, (address(0), address(0))) + initCalldata: abi.encodeCall(SystemConfigGlobal.initialize, (address(0), address(0))) }) ); } @@ -377,7 +384,7 @@ contract Initializer_Test is CommonTest { function test_cannotReinitialize_succeeds() public { // Collect exclusions. uint256 j; - string[] memory excludes = new string[](17); + string[] memory excludes = new string[](20); // Contract is currently not being deployed as part of the standard deployment script. excludes[j++] = "src/L2/OptimismSuperchainERC20.sol"; // Periphery contracts don't get deployed as part of the standard deployment script. @@ -394,7 +401,6 @@ contract Initializer_Test is CommonTest { excludes[j++] = "src/dispute/PermissionedDisputeGame.sol"; excludes[j++] = "src/dispute/SuperPermissionedDisputeGame.sol"; excludes[j++] = "src/dispute/zk/OPSuccinctFaultDisputeGame.sol"; - excludes[j++] = "src/mutliproof/AggregateVerifier.sol"; // TODO: Eventually remove this exclusion. Same reason as above dispute contracts. excludes[j++] = "src/L1/OPContractsManager.sol"; // TODO: Eventually remove this exclusion. Same reason as above dispute contracts. @@ -404,8 +410,14 @@ contract Initializer_Test is CommonTest { excludes[j++] = "src/L1/FeesDepositor.sol"; // Contract is not deployed as part of the standard deployment script. excludes[j++] = "src/revenue-share/BalanceTracker.sol"; - // Mock contracts are not deployed as part of the standard deployment script. + // Multiproof mocks are not deployed as part of the standard deployment script. excludes[j++] = "src/multiproof/mocks/*"; + // AggregateVerifier uses a custom `bool initialized` instead of OpenZeppelin's `_initialized` uint8. + excludes[j++] = "src/multiproof/AggregateVerifier.sol"; + // ETHLockbox is only deployed when interop is enabled. + if (address(ethLockbox) == address(0)) { + excludes[j++] = "src/L1/ETHLockbox.sol"; + } // Get all contract names in the src directory, minus the excluded contracts. string[] memory contractNames = ForgeArtifacts.getContractNames("src/*", excludes);