From ea588ffa3bbcf29bef243206ebf9f06e89e0fa96 Mon Sep 17 00:00:00 2001 From: Joby Thundil Date: Fri, 6 Mar 2026 13:06:26 -0500 Subject: [PATCH 01/18] feat(CHAIN-3293) Migrate Multiproof Contracts to base/contracts (#196) * initial commit * Refactor tests and simplify verifier * Refactor proof verification methods to consolidate TEE and ZK proof handling into a single function, improving code clarity and maintainability. Update tests accordingly to reflect the new verification structure. * refactor tests and errors * Prevent proofs from extending resolution time * ZK proof allows game creator to immediately reclaim bond * Additional tests * Refactor test cases to standardize warp duration and improve naming conventions for clarity in Nullify tests. * Add validation to ensure parent game has a proof before creating a child game in AggregateVerifier. Implement corresponding test case to verify this behavior. * Use calldata and remove unused variable * Make internal verify functions consistent * fix: can claim bond after nullifying a challenge * prevent challenges if parent or game itself is invalid * Enhance AggregateVerifier to include hashes for TEE and ZK images, and rollup configuration. Update verification methods to use a journal hash instead of root claims. Modify MockVerifier and tests accordingly. * Add ReentrancyGuard to AggregateVerifier and protect claimCredit function * Add constant for initialize calldata size in AggregateVerifier and update validation check to use this constant * Add test to validate failure on invalid calldata size in AggregateVerifier * Refactor l2BlockNumber function to l2SequenceNumber in AggregateVerifier, updating documentation and logic to clarify its purpose as the L2 sequence number. * Refactor visibility of state variables in AggregateVerifier from internal to public, enhancing accessibility for contract interactions. * Moved wasRespectedGameTypeWhenCreated for storage optimization * Remove underscores from constructor variables * IDIsputeGame compliance * Remove implicit returns * Add CreditClaimed event and update claimCredit logic in AggregateVerifier to emit event upon credit transfer * Rename getParentGameStatus to _getParentGameStatus in AggregateVerifier for consistency with internal function naming conventions. * Refactor return logic in getParentGameStatus to improve clarity by consolidating the return statement for the first dispute game scenario. * solidity style guide * forge fmt * Fix tests * remove unused imports * Named imports, reorganized imports, defined errors directly * linter * Add underscores to deal with compiler warnings * Refactor and have consistent comments * Update verifier interface to include image ID * Added feature where a proof is required for initialization * Added feature where a proof is required for initialization * Add back in IDisputeGame inheritance * forge fmt * refactor proof format * game type validation on challenging game * Add delayedWETH * forge fmt * Check challenging game validity when claiming credit * Add TEEVerifier and SystemConfigGlobal contracts and update AggregateVerifier to include l1OriginNumber in journal * fix(TEEVerifier): use correct EIP-2935 address and raw calldata for blockhash lookups * Refactor TEE contracts and deployment script based on PR review feedback * Refactor TEE contracts and deployment script based on PR review feedback * Remove underscore-prefixed parameters from mock contracts per style guide * Add comprehensive tests for TEEVerifier, SystemConfigGlobal, and DevSystemConfigGlobal; fix proof format in existing tests * Update teeProposer to match proposer address * correct teeImageHash in Sepolia deploy config * Moving TEE proposer to TEEVerifier * fix TEE comment * feat: intermediate roots for nullification * move L1 origin hash check from TEEVerifier to AggregateVerifier * fix tests * forge fmt * feat: split deploy configs and scripts into no-nitro and with-nitro variants * refactor _verifyProof * added block interval tests and cleaned up some errors * forge fmt * verify proof earlier during initialize * revert last commit * refactor initialize * refactor * fix: register TEE proposer during deployment and add intermediateBlockInterval to WithNitro script * use l1head for proofs after initialization * forge fmt * Fix comments from PR feedback Co-authored-by: Leopold Joy * step 1 fix dependencies and op commit * make multiproof compatible with base contracts * fix imports in scripts * fix mocks * format and seperate out multiproof tests * add tests to just and gen semver * fix tests * rm unecessary op commit * apply optimism patch for multiproof * move multiproof tests * move files and delete multiproof test usage and profile * remove remappings of nitro and op enclave * undo multiproof changes and solady import change * support AggregateVerifier in initalizer test * fix import path * semver * semver * semver * deterministic semverlock * add comment * refactor multiproof patch changes. fix typo * semver * fmt * semver * fix tests * fix tests where bytecodes size was different * fmt * semver * semver * semver * make aggregateverifies excluded like faultdispute game. fix systemconfiggloabal initialize * fmt * fix tests * semver * rm just test-multiproof * Replace onchain Nitro cert verification with Automata ZK verifier (#197) * Replace onchain Nitro cert verification with Automata ZK verifier, add ISemver to multiproof contracts, wire SystemConfigGlobal into standard deploy pipeline * Integrate multiproof config into standard DeployConfig, fix TEEVerifier proof format to match AggregateVerifier's l1head change * Fix fmt * Replace aws-nitro-enclave-attestation submodule with no-git dependency in Makefile * Consolidate deploy configs: migrate dev scripts to standard DeployConfig, add multiproof fields to sepolia.json and hardhat.json, remove separate nitro config files * Regenerate snapshots for updated and new multiproof contracts * Fix Initializable test: guard ETHLockbox entries for non-interop deploys, exclude AggregateVerifier (uses custom bool instead of OZ _initialized) * Add test-multiproof recipe to Justfile for CI * Address PR feedback: extract GameType local var, stricter pubKey check, iterate PCRs, add nitroEnclaveVerifier to Input, revert sepolia.json owner, remove redundant CI recipe * Resolve merge conflicts and regenerate semver-lock snapshots * Regenerate semver-lock with CI profile for correct bytecode hashes * Regenerate semver-lock with all compiler profiles including dispute * Regenerate semver-lock.json to remove stale dispute profile entries * Fix misleading TEEVerifier comment, require nitroEnclaveVerifier in deploy config, and parameterize hardcoded l2ChainID/block intervals in DeployImplementations * Reset semvar versioning in SystemConfigGlobal * Regenerate semver-lock.json for SystemConfigGlobal and TEEVerifier changes * correct SystemConfigGlobal.t.sol testInitialization() test cases to check correct version() number * use a proof threshold and allow ZK proofs after TEE nullification (#199) * use a proof threshold and allow ZK proofs after TEE nullification * pr feedback * update deployment scripts and tests * allow tee nullfiication when a zk proof exists. extend timestamp in this case to allow for zk nullification * Fix stack-too-deep in DeployImplementations and regenerate semver-lock * add multiproofProofThreshold to DeployConfig.s.sol to fix CI failures * Correct semver comment * Regenerate semver-lock following fix --------- Co-authored-by: roger-bai-coinbase * pr feedback: delete unecessary snapshots --------- Co-authored-by: Roger Bai Co-authored-by: Leopold Joy --- .gitignore | 3 + Makefile | 5 +- deploy-config/hardhat.json | 12 +- deploy-config/sepolia.json | 12 +- deployments/11155111-dev-no-nitro.json | 1 + foundry.toml | 21 +- interfaces/dispute/IDisputeGameFactory.sol | 9 + interfaces/dispute/IInitializable.sol | 1 + interfaces/multiproof/IVerifier.sol | 6 + scripts/autogen/generate-semver-lock/main.go | 10 + scripts/deploy/Deploy.s.sol | 10 + scripts/deploy/DeployConfig.s.sol | 22 + scripts/deploy/DeployImplementations.s.sol | 53 + scripts/libraries/ForgeArtifacts.sol | 8 +- scripts/multiproof/DeployDevNoNitro.s.sol | 250 ++++ scripts/multiproof/DeployDevWithNitro.s.sol | 292 +++++ .../multiproof/mocks/MinimalProxyAdmin.sol | 14 + .../mocks/MockAnchorStateRegistry.sol | 89 ++ scripts/multiproof/mocks/MockDelayedWETH.sol | 23 + snapshots/abi/AggregateVerifier.json | 1068 +++++++++++++++++ snapshots/abi/BalanceTracker.json | 194 +++ snapshots/abi/CBMulticall.json | 485 ++++++++ snapshots/abi/DisputeGameFactory.json | 34 + snapshots/abi/FeeDisburser.json | 182 +++ snapshots/abi/OPSuccinctFaultDisputeGame.json | 13 + snapshots/abi/Recovery.json | 138 +++ snapshots/abi/SmartEscrow.json | 977 +++++++++++++++ snapshots/abi/SuperchainConfig.json | 104 +- snapshots/abi/SystemConfigGlobal.json | 440 +++++++ snapshots/abi/TEEVerifier.json | 116 ++ snapshots/semver-lock.json | 56 +- .../storageLayout/AggregateVerifier.json | 93 ++ snapshots/storageLayout/BalanceTracker.json | 44 + snapshots/storageLayout/CBMulticall.json | 1 + snapshots/storageLayout/FeeDisburser.json | 16 + snapshots/storageLayout/Recovery.json | 1 + snapshots/storageLayout/SmartEscrow.json | 79 ++ snapshots/storageLayout/SuperchainConfig.json | 23 +- .../storageLayout/SystemConfigGlobal.json | 65 + snapshots/storageLayout/TEEVerifier.json | 1 + src/dispute/DisputeGameFactory.sol | 82 +- src/dispute/zk/OPSuccinctFaultDisputeGame.sol | 2 + src/multiproof/AggregateVerifier.sol | 991 +++++++++++++++ .../mocks/MockDevSystemConfigGlobal.sol | 25 + src/multiproof/mocks/MockSystemConfig.sol | 14 + src/multiproof/mocks/MockVerifier.sol | 10 + src/multiproof/tee/SystemConfigGlobal.sol | 173 +++ src/multiproof/tee/TEEVerifier.sol | 89 ++ test/libraries/SemverComp.t.sol | 2 +- test/multiproof/AggregateVerifier.t.sol | 406 +++++++ test/multiproof/BaseTest.t.sol | 211 ++++ test/multiproof/Challenge.t.sol | 234 ++++ test/multiproof/Nullify.t.sol | 158 +++ test/multiproof/SystemConfigGlobal.t.sol | 397 ++++++ test/multiproof/TEEVerifier.t.sol | 149 +++ test/opcm/DeployImplementations.t.sol | 16 + test/opcm/DeployOPChain.t.sol | 8 + test/setup/Setup.sol | 6 + test/vendor/Initializable.t.sol | 58 +- 59 files changed, 7867 insertions(+), 135 deletions(-) create mode 100644 deployments/11155111-dev-no-nitro.json create mode 100644 interfaces/multiproof/IVerifier.sol create mode 100644 scripts/multiproof/DeployDevNoNitro.s.sol create mode 100644 scripts/multiproof/DeployDevWithNitro.s.sol create mode 100644 scripts/multiproof/mocks/MinimalProxyAdmin.sol create mode 100644 scripts/multiproof/mocks/MockAnchorStateRegistry.sol create mode 100644 scripts/multiproof/mocks/MockDelayedWETH.sol create mode 100644 snapshots/abi/AggregateVerifier.json create mode 100644 snapshots/abi/BalanceTracker.json create mode 100644 snapshots/abi/CBMulticall.json create mode 100644 snapshots/abi/FeeDisburser.json create mode 100644 snapshots/abi/Recovery.json create mode 100644 snapshots/abi/SmartEscrow.json create mode 100644 snapshots/abi/SystemConfigGlobal.json create mode 100644 snapshots/abi/TEEVerifier.json create mode 100644 snapshots/storageLayout/AggregateVerifier.json create mode 100644 snapshots/storageLayout/BalanceTracker.json create mode 100644 snapshots/storageLayout/CBMulticall.json create mode 100644 snapshots/storageLayout/FeeDisburser.json create mode 100644 snapshots/storageLayout/Recovery.json create mode 100644 snapshots/storageLayout/SmartEscrow.json create mode 100644 snapshots/storageLayout/SystemConfigGlobal.json create mode 100644 snapshots/storageLayout/TEEVerifier.json create mode 100644 src/multiproof/AggregateVerifier.sol create mode 100644 src/multiproof/mocks/MockDevSystemConfigGlobal.sol create mode 100644 src/multiproof/mocks/MockSystemConfig.sol create mode 100644 src/multiproof/mocks/MockVerifier.sol create mode 100644 src/multiproof/tee/SystemConfigGlobal.sol create mode 100644 src/multiproof/tee/TEEVerifier.sol create mode 100644 test/multiproof/AggregateVerifier.t.sol create mode 100644 test/multiproof/BaseTest.t.sol create mode 100644 test/multiproof/Challenge.t.sol create mode 100644 test/multiproof/Nullify.t.sol create mode 100644 test/multiproof/SystemConfigGlobal.t.sol create mode 100644 test/multiproof/TEEVerifier.t.sol 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 2372124ca..9fdfbdbe9 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,10 @@ deps: clean-lib github.com/OpenZeppelin/openzeppelin-contracts-upgradeable@0a2cb9a445c365870ed7a8ab461b12acf3e27d63 \ github.com/transmissions11/solmate@8f9b23f8838670afda0fd8983f2c41e8037ae6bc \ github.com/safe-global/safe-contracts@bf943f80fec5ac647159d26161446ac5d716a294 \ - github.com/Vectorized/solady@502cc1ea718e6fa73b380635ee0868b0740595f0 + github.com/Vectorized/solady@502cc1ea718e6fa73b380635ee0868b0740595f0 \ + github.com/base/nitro-validator@0f006d2075637dd9640e530c4a7065f5c8bb2132 \ + 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.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/foundry.toml b/foundry.toml index 058cad23c..44da9da93 100644 --- a/foundry.toml +++ b/foundry.toml @@ -21,6 +21,7 @@ additional_compiler_profiles = [ { name = "dispute", optimizer_runs = 5000 }, ] compilation_restrictions = [ + { paths = "src/dispute/DisputeGameFactory.sol", optimizer_runs = 5000 }, { paths = "src/dispute/FaultDisputeGame.sol", optimizer_runs = 5000 }, { paths = "src/dispute/v2/FaultDisputeGameV2.sol", optimizer_runs = 5000 }, { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 5000 }, @@ -29,7 +30,15 @@ compilation_restrictions = [ { paths = "src/L1/OPContractsManager.sol", optimizer_runs = 5000 }, { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 5000 }, { paths = "src/L1/OptimismPortal2.sol", optimizer_runs = 5000 }, - { paths = "src/L1/ProtocolVersions.sol", optimizer_runs = 5000 } + { paths = "src/L1/ProtocolVersions.sol", optimizer_runs = 5000 }, + { paths = "src/L1/SystemConfig.sol", optimizer_runs = 5000 }, + { paths = "src/universal/OptimismMintableERC20Factory.sol", optimizer_runs = 5000 }, + { paths = "src/dispute/AnchorStateRegistry.sol", optimizer_runs = 5000 }, + { paths = "src/dispute/DelayedWETH.sol", optimizer_runs = 5000 }, + { paths = "src/universal/ProxyAdmin.sol", optimizer_runs = 5000 }, + { paths = "src/universal/Proxy.sol", optimizer_runs = 5000 }, + { paths = "src/L2/OptimismMintableERC721.sol", optimizer_runs = 5000 }, + { paths = "src/L2/OptimismMintableERC721Factory.sol", optimizer_runs = 5000 }, ] extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout'] @@ -43,6 +52,7 @@ remappings = [ '@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts', '@rari-capital/solmate/=lib/solmate', '@lib-keccak/=lib/lib-keccak/contracts/lib', + 'solady/=lib/solady/src/', '@solady/=lib/solady/src', '@solady-v0.0.245/=lib/solady-v0.0.245/src', 'forge-std/=lib/forge-std/src', @@ -153,6 +163,7 @@ additional_compiler_profiles = [ { name = "dispute", optimizer_runs = 0 }, ] compilation_restrictions = [ + { paths = "src/dispute/DisputeGameFactory.sol", optimizer_runs = 0 }, { paths = "src/dispute/FaultDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/v2/FaultDisputeGameV2.sol", optimizer_runs = 0 }, { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 0 }, @@ -162,6 +173,14 @@ compilation_restrictions = [ { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 0 }, { paths = "src/L1/OptimismPortal2.sol", optimizer_runs = 0 }, { paths = "src/L1/ProtocolVersions.sol", optimizer_runs = 0 }, + { paths = "src/L1/SystemConfig.sol", optimizer_runs = 0 }, + { paths = "src/universal/OptimismMintableERC20Factory.sol", optimizer_runs = 0 }, + { paths = "src/dispute/AnchorStateRegistry.sol", optimizer_runs = 0 }, + { paths = "src/dispute/DelayedWETH.sol", optimizer_runs = 0 }, + { paths = "src/universal/ProxyAdmin.sol", optimizer_runs = 0 }, + { paths = "src/universal/Proxy.sol", optimizer_runs = 0 }, + { paths = "src/L2/OptimismMintableERC721.sol", optimizer_runs = 0 }, + { paths = "src/L2/OptimismMintableERC721Factory.sol", optimizer_runs = 0 }, ] ################################################################ diff --git a/interfaces/dispute/IDisputeGameFactory.sol b/interfaces/dispute/IDisputeGameFactory.sol index da99c869a..91cc2ce89 100644 --- a/interfaces/dispute/IDisputeGameFactory.sol +++ b/interfaces/dispute/IDisputeGameFactory.sol @@ -34,6 +34,15 @@ interface IDisputeGameFactory is IProxyAdminOwnedBase, IReinitializableBase { external payable returns (IDisputeGame proxy_); + function createWithInitData( + GameType _gameType, + Claim _rootClaim, + bytes memory _extraData, + bytes memory initData + ) + external + payable + returns (IDisputeGame proxy_); function findLatestGames( GameType _gameType, uint256 _start, diff --git a/interfaces/dispute/IInitializable.sol b/interfaces/dispute/IInitializable.sol index a3bb74b82..c66ec9f82 100644 --- a/interfaces/dispute/IInitializable.sol +++ b/interfaces/dispute/IInitializable.sol @@ -3,4 +3,5 @@ pragma solidity ^0.8.0; interface IInitializable { function initialize() external payable; + function initializeWithInitData(bytes calldata initData) external payable; } diff --git a/interfaces/multiproof/IVerifier.sol b/interfaces/multiproof/IVerifier.sol new file mode 100644 index 000000000..d6a6b8745 --- /dev/null +++ b/interfaces/multiproof/IVerifier.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +interface IVerifier { + function verify(bytes calldata proofBytes, bytes32 imageId, bytes32 journal) external view returns (bool); +} diff --git a/scripts/autogen/generate-semver-lock/main.go b/scripts/autogen/generate-semver-lock/main.go index 9fb9f2103..44eb9d5ce 100644 --- a/scripts/autogen/generate-semver-lock/main.go +++ b/scripts/autogen/generate-semver-lock/main.go @@ -81,6 +81,16 @@ func processFile(file string) (*SemverLockResult, []error) { sourceFilePath = path contractName = name contractKey = sourceFilePath + ":" + name + if strings.HasSuffix(file, ".dispute.json") { + // We have an additional compiler profile called "dispute". + // This can produce different bytecode for certain contracts + // and the output will contain 2 jsons: .sol and + // .dispute.sol. These both produce the same contractKey + // since the CompilationTarget is the same. However, this leads to + // non-determinstic initCode hashes. Here, we make the contractKey + // unique thus guranteeing deterministic hashes. + contractKey += ":dispute" + } break } diff --git a/scripts/deploy/Deploy.s.sol b/scripts/deploy/Deploy.s.sol index 1b029609f..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, @@ -300,6 +308,8 @@ contract Deploy is Deployer { artifacts.save("DelayedWETHImpl", address(dio.delayedWETHImpl)); artifacts.save("PreimageOracle", address(dio.preimageOracleSingleton)); artifacts.save("PermissionedDisputeGame", address(dio.permissionedDisputeGameV2Impl)); + artifacts.save("AggregateVerifier", address(dio.aggregateVerifierImpl)); + artifacts.save("SystemConfigGlobal", address(dio.systemConfigGlobalImpl)); // Get a contract set from the implementation addresses which were just deployed. Types.ContractSet memory impls = ChainAssertions.dioToContractSet(dio); 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 7a45a2152..a4676f0d2 100644 --- a/scripts/deploy/DeployImplementations.s.sol +++ b/scripts/deploy/DeployImplementations.s.sol @@ -39,10 +39,19 @@ import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol"; import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IOPContractsManagerStandardValidator } from "interfaces/L1/IOPContractsManagerStandardValidator.sol"; +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; 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 { + 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 { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; +import { GameType } from "src/dispute/lib/Types.sol"; contract DeployImplementations is Script { struct Input { @@ -58,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; @@ -95,6 +113,8 @@ contract DeployImplementations is Script { IPermissionedDisputeGameV2 permissionedDisputeGameV2Impl; ISuperFaultDisputeGame superFaultDisputeGameImpl; ISuperPermissionedDisputeGame superPermissionedDisputeGameImpl; + IVerifier aggregateVerifierImpl; + SystemConfigGlobal systemConfigGlobalImpl; } bytes32 internal _salt = DeployUtils.DEFAULT_SALT; @@ -128,6 +148,7 @@ contract DeployImplementations is Script { deployAnchorStateRegistryImpl(_input, output_); deployFaultDisputeGameV2Impl(_input, output_); deployPermissionedDisputeGameV2Impl(_input, output_); + deployAggregateVerifierImpl(_input, output_); if (DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPTIMISM_PORTAL_INTEROP)) { deploySuperFaultDisputeGameImpl(_input, output_); deploySuperPermissionedDisputeGameImpl(_input, output_); @@ -695,6 +716,38 @@ contract DeployImplementations is Script { _output.opcmStandardValidator = impl; } + function deployAggregateVerifierImpl(Input memory _input, Output memory _output) private { + address zkVerifier = address(new MockVerifier()); + + 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( + GameType.wrap(uint32(_input.multiproofGameType)), + _output.anchorStateRegistryImpl, + _output.delayedWETHImpl, + IVerifier(teeVerifierImpl), + IVerifier(zkVerifier), + _input.teeImageHash, + bytes32(0), + _input.multiproofConfigHash, + _input.l2ChainID, + _input.multiproofBlockInterval, + _input.multiproofIntermediateBlockInterval, + _input.multiproofProofThreshold + ) + ) + ); + vm.label(address(_output.aggregateVerifierImpl), "AggregateVerifierImpl"); + } + function assertValidInput(Input memory _input) private pure { // Validate V2 game depth parameters are sensible require( diff --git a/scripts/libraries/ForgeArtifacts.sol b/scripts/libraries/ForgeArtifacts.sol index f49faec8a..a15f799d7 100644 --- a/scripts/libraries/ForgeArtifacts.sol +++ b/scripts/libraries/ForgeArtifacts.sol @@ -152,10 +152,14 @@ library ForgeArtifacts { /// @notice Pulls the `_initialized` storage slot information from the Forge artifacts for a given contract. function getInitializedSlot(string memory _contractName) internal returns (StorageSlot memory slot_) { - // FaultDisputeGame and PermissionedDisputeGame use a different name for the initialized storage slot. + // FaultDisputeGame, PermissionedDisputeGame, and AggregateVerifier use a different name for the initialized + // storage slot. string memory slotName = "_initialized"; string memory slotType = "t_uint8"; - if (LibString.eq(_contractName, "FaultDisputeGame") || LibString.eq(_contractName, "PermissionedDisputeGame")) { + if ( + LibString.eq(_contractName, "FaultDisputeGame") || LibString.eq(_contractName, "PermissionedDisputeGame") + || LibString.eq(_contractName, "AggregateVerifier") + ) { slotName = "initialized"; slotType = "t_bool"; } diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol new file mode 100644 index 000000000..04f5cc9e3 --- /dev/null +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/** + * @title DeployDevNoNitro + * @notice Development deployment WITHOUT AWS Nitro attestation validation. + * + * ══════════════════════════════════════════════════════════════════════════════════ + * DEPLOYMENT TYPE: DEV (NO NITRO) + * ══════════════════════════════════════════════════════════════════════════════════ + * + * This script deploys infrastructure using DevSystemConfigGlobal, which BYPASSES + * AWS Nitro attestation validation. Signers can be registered with a simple call + * to addDevSigner() without needing a real Nitro enclave or attestation document. + * + * USE THIS SCRIPT WHEN: + * - Running local development or testing + * - You don't have access to an AWS Nitro enclave + * - You want to quickly test the prover without attestation overhead + * + * DO NOT USE THIS SCRIPT FOR: + * - Production deployments + * - Security testing of the attestation flow + * + * ───────────────────────────────────────────────────────────────────────────────── + * SIGNER REGISTRATION (SIMPLIFIED) + * ───────────────────────────────────────────────────────────────────────────────── + * + * After deployment, register a signer with a single call: + * + * cast send $SYSTEM_CONFIG_GLOBAL \ + * "addDevSigner(address,bytes32)" $SIGNER_ADDRESS $TEE_IMAGE_HASH \ + * --private-key $OWNER_KEY --rpc-url $RPC_URL + * + * No attestation, PCR0 registration, or certificate validation required. + * + * ───────────────────────────────────────────────────────────────────────────────── + * COMPARISON WITH DeployDevWithNitro + * ───────────────────────────────────────────────────────────────────────────────── + * + * | Feature | DeployDevNoNitro | DeployDevWithNitro | + * |----------------------------|----------------------|------------------------| + * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | + * | Signer registration | addDevSigner() | registerSigner() | + * | Requires Nitro enclave | No | Yes | + * | Validates attestation (ZK) | No | Yes | + * | PCR0 pre-registration | No | Yes | + * | Attestation freshness | N/A | < 60 minutes | + * + * Both scripts use mocks for AnchorStateRegistry, DelayedWETH, and ZK Verifier. + * + * ══════════════════════════════════════════════════════════════════════════════════ + */ + +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 { console2 as console } from "forge-std/console2.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; +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"; +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 { MinimalProxyAdmin } from "./mocks/MinimalProxyAdmin.sol"; +import { MockAnchorStateRegistry } from "./mocks/MockAnchorStateRegistry.sol"; +import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; + +/// @title DeployDevNoNitro +/// @notice Development deployment WITHOUT AWS Nitro attestation validation. +/// @dev Uses DevSystemConfigGlobal which allows addDevSigner() to bypass attestation. +contract DeployDevNoNitro is Script { + /// @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; + + DeployConfig public constant cfg = + DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); + + // Deployed addresses + address public systemConfigGlobalProxy; + address public teeVerifier; + address public disputeGameFactory; + address public mockAnchorRegistry; + address public mockDelayedWETH; + address public aggregateVerifier; + + function setUp() public { + DeployUtils.etchLabelAndAllowCheatcodes({ _etchTo: address(cfg), _cname: "DeployConfig" }); + cfg.read(Config.deployConfigPath()); + } + + function run() public { + GameType gameType = GameType.wrap(uint32(cfg.multiproofGameType())); + + console.log("=== Deploying Dev Infrastructure (NO NITRO) ==="); + console.log("Chain ID:", block.chainid); + 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.finalSystemOwner()); + _registerProposer(cfg.teeProposer()); + _deployInfrastructure(gameType); + _deployAggregateVerifier(gameType); + + vm.stopBroadcast(); + + _printSummary(); + _writeOutput(); + } + + function _deployTEEContracts(address owner) internal { + address scgImpl = address(new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0)))); + systemConfigGlobalProxy = address( + new TransparentUpgradeableProxy( + scgImpl, address(0xdead), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + ) + ); + console.log("DevSystemConfigGlobal:", systemConfigGlobalProxy); + + teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); + console.log("TEEVerifier:", teeVerifier); + } + + function _registerProposer(address teeProposer) internal { + SystemConfigGlobal(systemConfigGlobalProxy).setProposer(teeProposer, true); + console.log("Registered TEE proposer:", teeProposer); + } + + function _deployInfrastructure(GameType gameType) internal { + address factoryImpl = address(new DisputeGameFactory()); + 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.finalSystemOwner()); + + disputeGameFactory = address(proxy); + console.log("DisputeGameFactory:", disputeGameFactory); + + MockAnchorStateRegistry asr = new MockAnchorStateRegistry(); + mockAnchorRegistry = address(asr); + asr.initialize( + disputeGameFactory, + Hash.wrap(cfg.multiproofGenesisOutputRoot()), + cfg.multiproofGenesisBlockNumber(), + gameType + ); + console.log("AnchorStateRegistry (mock):", mockAnchorRegistry); + } + + function _deployAggregateVerifier(GameType gameType) internal { + address zkVerifier = address(new MockVerifier()); + console.log("MockVerifier (ZK):", zkVerifier); + + mockDelayedWETH = address(new MockDelayedWETH()); + console.log("MockDelayedWETH:", mockDelayedWETH); + + aggregateVerifier = address( + new AggregateVerifier( + gameType, + IAnchorStateRegistry(mockAnchorRegistry), + IDelayedWETH(payable(mockDelayedWETH)), + IVerifier(teeVerifier), + IVerifier(zkVerifier), + cfg.teeImageHash(), + bytes32(0), + cfg.multiproofConfigHash(), + 8453, + BLOCK_INTERVAL, + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD + ) + ); + console.log("AggregateVerifier:", aggregateVerifier); + + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); + console.log("Registered AggregateVerifier with factory"); + } + + function _printSummary() internal view { + console.log("\n========================================"); + console.log(" DEV DEPLOYMENT COMPLETE (NO NITRO)"); + console.log("========================================"); + console.log("\nTEE Contracts:"); + console.log(" DevSystemConfigGlobal:", systemConfigGlobalProxy); + console.log(" TEEVerifier:", teeVerifier); + console.log("\nInfrastructure:"); + console.log(" DisputeGameFactory:", disputeGameFactory); + console.log(" AnchorStateRegistry (mock):", mockAnchorRegistry); + console.log(" DelayedWETH (mock):", mockDelayedWETH); + console.log("\nGame:"); + console.log(" AggregateVerifier:", aggregateVerifier); + 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(cfg.teeImageHash())); + console.log(" --private-key --rpc-url "); + console.log("\n========================================\n"); + } + + function _writeOutput() internal { + string memory outPath = string.concat("deployments/", vm.toString(block.chainid), "-dev-no-nitro.json"); + string memory output = string.concat( + '{"SystemConfigGlobal":"', + vm.toString(systemConfigGlobalProxy), + '","TEEVerifier":"', + vm.toString(teeVerifier), + '","DisputeGameFactory":"', + vm.toString(disputeGameFactory), + '","AnchorStateRegistry":"', + vm.toString(mockAnchorRegistry), + '","DelayedWETH":"', + vm.toString(mockDelayedWETH), + '","AggregateVerifier":"', + vm.toString(aggregateVerifier), + '"}' + ); + vm.writeFile(outPath, output); + console.log("Deployment saved to:", outPath); + } +} diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol new file mode 100644 index 000000000..875674ae3 --- /dev/null +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/** + * @title DeployDevWithNitro + * @notice Development deployment WITH AWS Nitro attestation validation. + * + * ══════════════════════════════════════════════════════════════════════════════════ + * DEPLOYMENT TYPE: DEV (WITH NITRO) + * ══════════════════════════════════════════════════════════════════════════════════ + * + * This script deploys infrastructure using the REAL SystemConfigGlobal, which + * 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 + * - You have access to a real AWS Nitro enclave + * - You want to validate the production registration process + * + * DO NOT USE THIS SCRIPT IF: + * - You don't have a Nitro enclave available + * - You just want quick local testing (use DeployDevNoNitro instead) + * + * NOTE: This still uses mocks for AnchorStateRegistry, DelayedWETH, and ZK Verifier, + * so it's not a full production deployment - just production-like for the + * Nitro attestation flow. + * + * ───────────────────────────────────────────────────────────────────────────────── + * STEP 1: Register the PCR0 (enclave image hash) - OWNER ONLY + * ───────────────────────────────────────────────────────────────────────────────── + * + * The PCR0 is the raw 48-byte hash of the enclave image. You must register it + * before any signers using that image can be registered. + * + * # Get raw PCR0 bytes from the enclave (48 bytes, hex-encoded) + * PCR0_RAW="0x<48_bytes_hex>" + * + * # Register it (only owner can do this) + * cast send $SYSTEM_CONFIG_GLOBAL "registerPCR0(bytes)" $PCR0_RAW \ + * --private-key $OWNER_KEY --rpc-url $RPC_URL + * + * Note: The teeImageHash in deploy-config is keccak256(PCR0_RAW), not the raw bytes. + * + * ───────────────────────────────────────────────────────────────────────────────── + * STEP 2: Generate ZK proof of the attestation and register the signer + * ───────────────────────────────────────────────────────────────────────────────── + * + * Generate a Risc0 ZK proof of the Nitro attestation offchain, then call: + * + * cast send $SYSTEM_CONFIG_GLOBAL \ + * "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 + * ───────────────────────────────────────────────────────────────────────────────── + * + * After registration, verify the signer is registered: + * + * # Check if signer is valid + * cast call $SYSTEM_CONFIG_GLOBAL "isValidSigner(address)(bool)" $SIGNER_ADDRESS + * + * # Get the PCR0 hash associated with the signer + * cast call $SYSTEM_CONFIG_GLOBAL "signerPCR0(address)(bytes32)" $SIGNER_ADDRESS + * + * ───────────────────────────────────────────────────────────────────────────────── + * COMPARISON WITH DeployDevNoNitro + * ───────────────────────────────────────────────────────────────────────────────── + * + * | Feature | DeployDevNoNitro | DeployDevWithNitro | + * |----------------------------|----------------------|------------------------| + * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | + * | Signer registration | addDevSigner() | registerSigner() | + * | Requires Nitro enclave | No | Yes | + * | Validates attestation (ZK) | No | Yes | + * | PCR0 pre-registration | No | Yes | + * | Attestation freshness | N/A | < 60 minutes | + * + * Both scripts use mocks for AnchorStateRegistry, DelayedWETH, and ZK Verifier. + * + * ══════════════════════════════════════════════════════════════════════════════════ + */ + +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 { console2 as console } from "forge-std/console2.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; +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"; +import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; + +import { MinimalProxyAdmin } from "./mocks/MinimalProxyAdmin.sol"; +import { MockAnchorStateRegistry } from "./mocks/MockAnchorStateRegistry.sol"; +import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; + +/// @title DeployDevWithNitro +/// @notice Development deployment WITH AWS Nitro attestation validation. +/// @dev Uses real SystemConfigGlobal which requires registerSigner() with valid attestation. +contract DeployDevWithNitro is Script { + /// @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; + + DeployConfig public constant cfg = + DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); + + // Deployed addresses + address public systemConfigGlobalProxy; + address public teeVerifier; + address public disputeGameFactory; + address public mockAnchorRegistry; + address public mockDelayedWETH; + address public aggregateVerifier; + + function setUp() public { + DeployUtils.etchLabelAndAllowCheatcodes({ _etchTo: address(cfg), _cname: "DeployConfig" }); + cfg.read(Config.deployConfigPath()); + } + + function run() public { + GameType gameType = GameType.wrap(uint32(cfg.multiproofGameType())); + + console.log("=== Deploying Dev Infrastructure (WITH NITRO) ==="); + console.log("Chain ID:", block.chainid); + 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 - ZK attestation proof REQUIRED."); + console.log("NitroEnclaveVerifier:", cfg.nitroEnclaveVerifier()); + + vm.startBroadcast(); + + _deployTEEContracts(cfg.finalSystemOwner(), cfg.nitroEnclaveVerifier()); + _registerProposer(cfg.teeProposer()); + _deployInfrastructure(gameType); + _deployAggregateVerifier(gameType); + + vm.stopBroadcast(); + + _printSummary(); + _writeOutput(); + } + + 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), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + ) + ); + console.log("SystemConfigGlobal:", systemConfigGlobalProxy); + + teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); + console.log("TEEVerifier:", teeVerifier); + } + + function _registerProposer(address teeProposer) internal { + SystemConfigGlobal(systemConfigGlobalProxy).setProposer(teeProposer, true); + console.log("Registered TEE proposer:", teeProposer); + } + + function _deployInfrastructure(GameType gameType) internal { + address factoryImpl = address(new DisputeGameFactory()); + 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.finalSystemOwner()); + + disputeGameFactory = address(proxy); + console.log("DisputeGameFactory:", disputeGameFactory); + + MockAnchorStateRegistry asr = new MockAnchorStateRegistry(); + mockAnchorRegistry = address(asr); + asr.initialize( + disputeGameFactory, + Hash.wrap(cfg.multiproofGenesisOutputRoot()), + cfg.multiproofGenesisBlockNumber(), + gameType + ); + console.log("AnchorStateRegistry (mock):", mockAnchorRegistry); + } + + function _deployAggregateVerifier(GameType gameType) internal { + address zkVerifier = address(new MockVerifier()); + console.log("MockVerifier (ZK):", zkVerifier); + + mockDelayedWETH = address(new MockDelayedWETH()); + console.log("MockDelayedWETH:", mockDelayedWETH); + + aggregateVerifier = address( + new AggregateVerifier( + gameType, + IAnchorStateRegistry(mockAnchorRegistry), + IDelayedWETH(payable(mockDelayedWETH)), + IVerifier(teeVerifier), + IVerifier(zkVerifier), + cfg.teeImageHash(), + bytes32(0), + cfg.multiproofConfigHash(), + 8453, + BLOCK_INTERVAL, + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD + ) + ); + console.log("AggregateVerifier:", aggregateVerifier); + + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); + console.log("Registered AggregateVerifier with factory"); + } + + function _printSummary() internal view { + console.log("\n========================================"); + console.log(" DEV DEPLOYMENT COMPLETE (WITH NITRO)"); + console.log("========================================"); + console.log("\nTEE Contracts:"); + console.log(" NitroEnclaveVerifier (external):", cfg.nitroEnclaveVerifier()); + console.log(" SystemConfigGlobal:", systemConfigGlobalProxy); + console.log(" TEEVerifier:", teeVerifier); + console.log("\nInfrastructure:"); + console.log(" DisputeGameFactory:", disputeGameFactory); + console.log(" AnchorStateRegistry (mock):", mockAnchorRegistry); + console.log(" DelayedWETH (mock):", mockDelayedWETH); + console.log("\nGame:"); + console.log(" AggregateVerifier:", aggregateVerifier); + 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 (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. 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"); + } + + function _writeOutput() internal { + string memory outPath = string.concat("deployments/", vm.toString(block.chainid), "-dev-with-nitro.json"); + string memory output = string.concat( + '{"SystemConfigGlobal":"', + vm.toString(systemConfigGlobalProxy), + '","TEEVerifier":"', + vm.toString(teeVerifier), + '","DisputeGameFactory":"', + vm.toString(disputeGameFactory), + '","AnchorStateRegistry":"', + vm.toString(mockAnchorRegistry), + '","DelayedWETH":"', + vm.toString(mockDelayedWETH), + '","AggregateVerifier":"', + vm.toString(aggregateVerifier), + '"}' + ); + vm.writeFile(outPath, output); + console.log("Deployment saved to:", outPath); + } +} diff --git a/scripts/multiproof/mocks/MinimalProxyAdmin.sol b/scripts/multiproof/mocks/MinimalProxyAdmin.sol new file mode 100644 index 000000000..ad46f7a4a --- /dev/null +++ b/scripts/multiproof/mocks/MinimalProxyAdmin.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/// @title MinimalProxyAdmin +/// @notice Minimal contract to satisfy DisputeGameFactory's proxy admin check. +/// @dev DisputeGameFactory.initialize() requires msg.sender == proxyAdmin() or proxyAdminOwner(). +/// We deploy this minimal contract and set it as the proxy admin via vm.store. +contract MinimalProxyAdmin { + address public owner; + + constructor(address initialOwner) { + owner = initialOwner; + } +} diff --git a/scripts/multiproof/mocks/MockAnchorStateRegistry.sol b/scripts/multiproof/mocks/MockAnchorStateRegistry.sol new file mode 100644 index 000000000..a4108dc4d --- /dev/null +++ b/scripts/multiproof/mocks/MockAnchorStateRegistry.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { GameType, Hash } from "src/dispute/lib/Types.sol"; + +/// @title MockAnchorStateRegistry +/// @notice Minimal mock for testing - stores anchor state and factory reference. +/// @dev We use a mock instead of the real AnchorStateRegistry because: +/// 1. The real contract requires deploying the entire Optimism L1 stack +/// (SystemConfig, SuperchainConfig, ProxyAdmin, Guardian roles, etc.) +/// 2. The real contract has "stack too deep" compilation issues that require +/// special compiler settings (via-ir) which significantly slow builds +/// 3. For TEE prover testing, we only need getAnchorRoot() and setAnchorState() +contract MockAnchorStateRegistry { + Hash public anchorRoot; + uint256 public anchorL2BlockNumber; + address public factory; + GameType public respectedGameType; + + /// @notice Initializes the mock registry. + /// @param newFactory The dispute game factory address. + /// @param newAnchorRoot The initial anchor root. + /// @param newAnchorL2BlockNumber The initial anchor L2 block number. + /// @param gameType The respected game type. + function initialize( + address newFactory, + Hash newAnchorRoot, + uint256 newAnchorL2BlockNumber, + GameType gameType + ) + external + { + factory = newFactory; + anchorRoot = newAnchorRoot; + anchorL2BlockNumber = newAnchorL2BlockNumber; + respectedGameType = gameType; + } + + /// @notice Returns the anchor root and block number. + /// @return The anchor root hash and L2 block number. + function getAnchorRoot() external view returns (Hash, uint256) { + return (anchorRoot, anchorL2BlockNumber); + } + + /// @notice Returns the dispute game factory address. + /// @return The factory address. + function disputeGameFactory() external view returns (address) { + return factory; + } + + /// @notice Sets the respected game type. + /// @param gameType The new game type. + function setRespectedGameType(GameType gameType) external { + respectedGameType = gameType; + } + + /// @notice Updates the anchor state (for testing purposes). + /// @param newAnchorRoot The new anchor root. + /// @param newAnchorL2BlockNumber The new anchor L2 block number. + function setAnchorState(Hash newAnchorRoot, uint256 newAnchorL2BlockNumber) external { + anchorRoot = newAnchorRoot; + anchorL2BlockNumber = newAnchorL2BlockNumber; + } + + /// @notice Checks if a game is registered. + /// @return Always returns true for testing. + function isGameRegistered(IDisputeGame) external pure returns (bool) { + return true; + } + + /// @notice Checks if a game is blacklisted. + /// @return Always returns false for testing. + function isGameBlacklisted(IDisputeGame) external pure returns (bool) { + return false; + } + + /// @notice Checks if a game is retired. + /// @return Always returns false for testing. + function isGameRetired(IDisputeGame) external pure returns (bool) { + return false; + } + + /// @notice Checks if a game is respected. + /// @return Always returns true for testing. + function isGameRespected(IDisputeGame) external pure returns (bool) { + return true; + } +} diff --git a/scripts/multiproof/mocks/MockDelayedWETH.sol b/scripts/multiproof/mocks/MockDelayedWETH.sol new file mode 100644 index 000000000..ddffec0b7 --- /dev/null +++ b/scripts/multiproof/mocks/MockDelayedWETH.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/// @title MockDelayedWETH +/// @notice Minimal mock for testing - implements the IDelayedWETH interface. +/// @dev For testing purposes only. The real DelayedWETH handles bond deposits and withdrawals. +contract MockDelayedWETH { + /// @notice Accepts ETH deposits (no-op for testing). + function deposit() external payable { } + + /// @notice Mock unlock - no-op for testing. + function unlock(address, uint256) external { } + + /// @notice Mock withdraw - transfers ETH back. + /// @param recipient The address to send ETH to. + /// @param amount The amount of ETH to withdraw. + function withdraw(address recipient, uint256 amount) external { + payable(recipient).transfer(amount); + } + + /// @notice Allows contract to receive ETH. + receive() external payable { } +} 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/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/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 5f3043e6d..08bc12a07 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -11,6 +11,10 @@ "initCodeHash": "0xe52c51805cfd55967d037173159f18aaf4344e32e5c8ad41f8d5d0025b1d36a8", "sourceCodeHash": "0xe5f2b1915a201c0b8a107f168f5b9bc8aec8e8e95f938082e42ba5b5c8ebbd11" }, + "src/L1/FeesDepositor.sol:FeesDepositor:dispute": { + "initCodeHash": "0xe52c51805cfd55967d037173159f18aaf4344e32e5c8ad41f8d5d0025b1d36a8", + "sourceCodeHash": "0xe5f2b1915a201c0b8a107f168f5b9bc8aec8e8e95f938082e42ba5b5c8ebbd11" + }, "src/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger": { "initCodeHash": "0x3dc659aafb03bd357f92abfc6794af89ee0ddd5212364551637422bf8d0b00f9", "sourceCodeHash": "0xfd67aae7ef1d684f3fccc036a80123e0ffa13de3e26c910cb7b927059c5a6289" @@ -47,8 +51,12 @@ "initCodeHash": "0x9b1f3555b499709485d51d5d9665002c0eb1e5eb893be1fb978a30749e894858", "sourceCodeHash": "0x572b5da38443fa5fc1c1873a733adee1894c6eba94f0e7867f2e81c5eb616a39" }, + "src/L1/SuperchainConfig.sol:SuperchainConfig:dispute": { + "initCodeHash": "0x9b1f3555b499709485d51d5d9665002c0eb1e5eb893be1fb978a30749e894858", + "sourceCodeHash": "0x572b5da38443fa5fc1c1873a733adee1894c6eba94f0e7867f2e81c5eb616a39" + }, "src/L1/SystemConfig.sol:SystemConfig": { - "initCodeHash": "0x184e74fa4993271e35d477155689ceba54c083c71f0f93f2dea0ee6330c61693", + "initCodeHash": "0x3e8e52d96398a6de91d8922769cc5d0bc7acb2a692689ceb70f1de816e8d6b14", "sourceCodeHash": "0x1a24ffe154eddbe0088a4b0848e662bf5eb482fe031ba528f74c51804f6e0395" }, "src/L2/BaseFeeVault.sol:BaseFeeVault": { @@ -128,11 +136,11 @@ "sourceCodeHash": "0xd6e94bc9df025855916aa4184d0bc739b0fbe786dfd037b99dbb51d0d3e46918" }, "src/L2/OptimismMintableERC721.sol:OptimismMintableERC721": { - "initCodeHash": "0x316c6d716358f5b5284cd5457ea9fca4b5ad4a37835d4b4b300413dafbfa2159", + "initCodeHash": "0x363dcb59140ecfbcdff7b5f4e822f0fdc8492fc02b6d9abf3cb822ae75e8dcfb", "sourceCodeHash": "0xd93a8d5de6fd89ebf503976511065f0c2414814affdb908f26a867ffdd0f9fbe" }, "src/L2/OptimismMintableERC721Factory.sol:OptimismMintableERC721Factory": { - "initCodeHash": "0xa692a3fc4a71eb3381a59d1ab655bbc02e8b507add7c3f560ee24b001d88ae6e", + "initCodeHash": "0x3f31209e30a79f367b59b66e3ee6f43f5916ec26e6d1c5a08846d636884f020d", "sourceCodeHash": "0xb0be3deac32956251adb37d3ca61f619ca4348a1355a41c856a3a95adde0e4ff" }, "src/L2/OptimismSuperchainERC20.sol:OptimismSuperchainERC20": { @@ -180,16 +188,16 @@ "sourceCodeHash": "0xd3fd2d07ea417c97590c5b1895890186faf7d1f12f1e2d368ba270d077c088fd" }, "src/dispute/AnchorStateRegistry.sol:AnchorStateRegistry": { - "initCodeHash": "0xc00fdb1a4ae0ec8d7a96ebaad38ffaee9d96b942ab2a56e0ce2f76639f79ae7c", + "initCodeHash": "0x4795cc818d507942e953f1ed412218f5cdbf5802a98e5fa1c73450dd6dfa39e9", "sourceCodeHash": "0x93fcf998d69b2a72273c4043c465010d53e338be95331cdd122ea55ff5bb0ef8" }, "src/dispute/DelayedWETH.sol:DelayedWETH": { - "initCodeHash": "0xa8f60e142108b33675a8f6b6979c73b96eea247884842d796f9f878904c0a906", + "initCodeHash": "0x592a6e22e1d02797eeb6fa622806e58f867bb6066944852e120b5871d3110825", "sourceCodeHash": "0xdebf2ab3af4d5549c40e9dd9db6b2458af286f323b6891f3b0c4e89f3c8928db" }, "src/dispute/DisputeGameFactory.sol:DisputeGameFactory": { - "initCodeHash": "0x820e876839f94564a9d5d1fa131781c40126aed76fbbd348f49f318ae3e12aae", - "sourceCodeHash": "0x870025c86292471724e2be703b181be8d71a7e1e96ebf181e0a81c005032a5db" + "initCodeHash": "0x727de8dbfd3432d95e19c39ece5ac7aec183dd67a09db769791d0e835e365d88", + "sourceCodeHash": "0x099527c6ecc13a98b6b9f09b7fcd4b44ffa351665e556df0bd0db344dd749da9" }, "src/dispute/FaultDisputeGame.sol:FaultDisputeGame": { "initCodeHash": "0xe7d3c982532946d196d7efadb9e2576c76b8f9e0d1f885ac36977d6f3fb72a65", @@ -216,8 +224,8 @@ "sourceCodeHash": "0xc0ff6e93b6e2b9111c11e81b5df8948ab71d02b9d2c4dfda982fcb615519f1f7" }, "src/dispute/zk/OPSuccinctFaultDisputeGame.sol:OPSuccinctFaultDisputeGame": { - "initCodeHash": "0xb9d0d9ca4df242f188b2d5be7d692459a12409a67a6504ef44ef589c6ca2c1a9", - "sourceCodeHash": "0x85f80adb845f59e9137d462e219c0cdba27058be77d855075e286aa316735aa0" + "initCodeHash": "0x70d20610e50b4eb713c33ce9b0a64200227f99efad88856f269316c6b789ecd1", + "sourceCodeHash": "0xce800b9bd50229b069793b44cf62823135034344a41dcd83e7a24428abe8483a" }, "src/legacy/DeployerWhitelist.sol:DeployerWhitelist": { "initCodeHash": "0x2e0ef4c341367eb59cc6c25190c64eff441d3fe130189da91d4d126f6bdbc9b5", @@ -231,6 +239,30 @@ "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": "0x76da4f2a736d7a39a01720e5d900a85fcaa60ba0430fcacbb8ab367f55ba5411", + "sourceCodeHash": "0xa6261402efe0105e2a4f9369818bafb4e65515e51850b44d47504151e1c39d01" + }, + "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal:dispute": { + "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", "sourceCodeHash": "0xac49a0ecf22b8a7bb3ebef830a2d27b19050f9b08941186e8563d5113cf0ce9c" @@ -255,8 +287,12 @@ "initCodeHash": "0x3c85eed0d017dca8eda6396aa842ddc12492587b061e8c756a8d32c4610a9658", "sourceCodeHash": "0x7023665d461f173417d932b55010b8f6c34f2bbaf56cfe4e1b15862c08cbcaac" }, + "src/universal/OptimismMintableERC20.sol:OptimismMintableERC20:dispute": { + "initCodeHash": "0xa26cd5b88cb1d4e5cef0422b98ff4c33a3bbfa33479ebd8632d095bb2c633ca7", + "sourceCodeHash": "0x7023665d461f173417d932b55010b8f6c34f2bbaf56cfe4e1b15862c08cbcaac" + }, "src/universal/OptimismMintableERC20Factory.sol:OptimismMintableERC20Factory": { - "initCodeHash": "0x747baf403205b900e1144038f2b807c84059229aedda8c91936798e1403eda39", + "initCodeHash": "0x75f5f8dad139fce79a2fed9c80bf653184c73fb7dc319715cdd07392f32b007a", "sourceCodeHash": "0xf71e16aaad1ec2459040ab8c93b7188b2c04c671c21b4d43fba75cab80ed1b21" }, "src/universal/StorageSetter.sol:StorageSetter": { 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/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/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/dispute/DisputeGameFactory.sol b/src/dispute/DisputeGameFactory.sol index 6129c8305..bdc189a58 100644 --- a/src/dispute/DisputeGameFactory.sol +++ b/src/dispute/DisputeGameFactory.sol @@ -139,18 +139,69 @@ contract DisputeGameFactory is ProxyAdminOwnedBase, ReinitializableBase, Ownable (gameType_, timestamp_, proxy_) = (gameType, timestamp, IDisputeGame(proxy)); } + function create( + GameType _gameType, + Claim _rootClaim, + bytes calldata _extraData + ) + external + payable + returns (IDisputeGame proxy_) + { + proxy_ = _createGameImpl(_gameType, _rootClaim, _extraData); + proxy_.initialize{ value: msg.value }(); + _finalizeGameCreation(_gameType, _rootClaim, _extraData, proxy_); + } + + function createWithInitData( + GameType _gameType, + Claim _rootClaim, + bytes calldata _extraData, + bytes calldata _initData + ) + external + payable + returns (IDisputeGame proxy_) + { + proxy_ = _createGameImpl(_gameType, _rootClaim, _extraData); + proxy_.initializeWithInitData{ value: msg.value }(_initData); + _finalizeGameCreation(_gameType, _rootClaim, _extraData, proxy_); + } + /// @notice Creates a new DisputeGame proxy contract. /// @param _gameType The type of the DisputeGame - used to decide the proxy implementation. /// @param _rootClaim The root claim of the DisputeGame. /// @param _extraData Any extra data that should be provided to the created dispute game. - /// @return proxy_ The address of the created DisputeGame proxy. - function create( + /// @param proxy_ The address of the created DisputeGame proxy. + function _finalizeGameCreation( + GameType _gameType, + Claim _rootClaim, + bytes calldata _extraData, + IDisputeGame proxy_ + ) + internal + { + // Compute the unique identifier for the dispute game. + Hash uuid = getGameUUID(_gameType, _rootClaim, _extraData); + + // If a dispute game with the same UUID already exists, revert. + if (GameId.unwrap(_disputeGames[uuid]) != bytes32(0)) revert GameAlreadyExists(uuid); + + // Pack the game ID. + GameId id = LibGameId.pack(_gameType, Timestamp.wrap(uint64(block.timestamp)), address(proxy_)); + + // Store the dispute game id in the mapping & emit the `DisputeGameCreated` event. + _disputeGames[uuid] = id; + _disputeGameList.push(id); + emit DisputeGameCreated(address(proxy_), _gameType, _rootClaim); + } + + function _createGameImpl( GameType _gameType, Claim _rootClaim, bytes calldata _extraData ) - external - payable + internal returns (IDisputeGame proxy_) { // Grab the implementation contract for the given `GameType`. @@ -165,7 +216,9 @@ contract DisputeGameFactory is ProxyAdminOwnedBase, ReinitializableBase, Ownable // Get the hash of the parent block. bytes32 parentHash = blockhash(block.number - 1); - if (gameArgs[_gameType].length == 0) { + // Cache gameArgs to avoid stack-too-deep errors + bytes memory implArgs = gameArgs[_gameType]; + if (implArgs.length == 0) { // Clone the implementation contract and initialize it with the given parameters. // // CWIA Calldata Layout: @@ -194,26 +247,9 @@ contract DisputeGameFactory is ProxyAdminOwnedBase, ReinitializableBase, Ownable // └──────────────────────┴─────────────────────────────────────┘ proxy_ = IDisputeGame( address(impl) - .clone( - abi.encodePacked(msg.sender, _rootClaim, parentHash, _gameType, _extraData, gameArgs[_gameType]) - ) + .clone(abi.encodePacked(msg.sender, _rootClaim, parentHash, _gameType, _extraData, implArgs)) ); } - proxy_.initialize{ value: msg.value }(); - - // Compute the unique identifier for the dispute game. - Hash uuid = getGameUUID(_gameType, _rootClaim, _extraData); - - // If a dispute game with the same UUID already exists, revert. - if (GameId.unwrap(_disputeGames[uuid]) != bytes32(0)) revert GameAlreadyExists(uuid); - - // Pack the game ID. - GameId id = LibGameId.pack(_gameType, Timestamp.wrap(uint64(block.timestamp)), address(proxy_)); - - // Store the dispute game id in the mapping & emit the `DisputeGameCreated` event. - _disputeGames[uuid] = id; - _disputeGameList.push(id); - emit DisputeGameCreated(address(proxy_), _gameType, _rootClaim); } /// @notice Returns a unique identifier for the given dispute game parameters. diff --git a/src/dispute/zk/OPSuccinctFaultDisputeGame.sol b/src/dispute/zk/OPSuccinctFaultDisputeGame.sol index f7c1e6e76..61579b105 100644 --- a/src/dispute/zk/OPSuccinctFaultDisputeGame.sol +++ b/src/dispute/zk/OPSuccinctFaultDisputeGame.sol @@ -321,6 +321,8 @@ contract OPSuccinctFaultDisputeGame is Clone, ISemver, IDisputeGame { GameType.unwrap(ANCHOR_STATE_REGISTRY.respectedGameType()) == GameType.unwrap(GAME_TYPE); } + function initializeWithInitData(bytes calldata) external payable { } + /// @notice The L2 block number for which this game is proposing an output root. function l2SequenceNumber() public pure returns (uint256 l2SequenceNumber_) { l2SequenceNumber_ = _getArgUint256(0x54); diff --git a/src/multiproof/AggregateVerifier.sol b/src/multiproof/AggregateVerifier.sol new file mode 100644 index 000000000..21d255d48 --- /dev/null +++ b/src/multiproof/AggregateVerifier.sol @@ -0,0 +1,991 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +// Optimism +import { + AlreadyInitialized, + BondTransferFailed, + ClaimAlreadyResolved, + GameNotFinalized, + GameNotInProgress, + GameNotResolved, + GamePaused, + NoCreditToClaim +} from "src/dispute/lib/Errors.sol"; +import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { Claim, GameStatus, GameType, Hash, Proposal, Timestamp } from "src/dispute/lib/Types.sol"; + +// Solady +import { Clone } from "@solady/utils/Clone.sol"; +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, ISemver { + //////////////////////////////////////////////////////////////// + // Enums // + //////////////////////////////////////////////////////////////// + + /// @notice The type of proof. Can be expanded for different types of ZK proofs. + enum ProofType { + TEE, + ZK + } + + //////////////////////////////////////////////////////////////// + // Constants // + //////////////////////////////////////////////////////////////// + /// @notice The slow finalization delay. + uint64 public constant SLOW_FINALIZATION_DELAY = 7 days; + + /// @notice The fast finalization delay. + uint64 public constant FAST_FINALIZATION_DELAY = 1 days; + + /// @notice The EIP-2935 blockhash history contract address (deployed post-Pectra). + /// @dev This contract stores blockhashes for the last ~8192 blocks, extending the + /// 256-block window of the native blockhash() opcode. + address public constant EIP2935_CONTRACT = 0x0000F90827F1C53a10cb7A02335B175320002935; + + /// @notice The maximum number of blocks that blockhash() can look back. + uint256 public constant BLOCKHASH_WINDOW = 256; + + /// @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 // + //////////////////////////////////////////////////////////////// + /// @notice The anchor state registry. + IAnchorStateRegistry internal immutable ANCHOR_STATE_REGISTRY; + + /// @notice The dispute game factory. + IDisputeGameFactory public immutable DISPUTE_GAME_FACTORY; + + /// @notice The delayed WETH contract. + IDelayedWETH public immutable DELAYED_WETH; + + /// @notice The TEE prover. + IVerifier public immutable TEE_VERIFIER; + + /// @notice The hash of the TEE image. + bytes32 public immutable TEE_IMAGE_HASH; + + /// @notice The ZK prover. + IVerifier public immutable ZK_VERIFIER; + + /// @notice The hash of the ZK image. + bytes32 public immutable ZK_IMAGE_HASH; + + /// @notice The hash of the rollup configuration. + bytes32 public immutable CONFIG_HASH; + + /// @notice The chain ID of the L2 network this contract argues about. + uint256 public immutable L2_CHAIN_ID; + + /// @notice The block interval between each proposal. + /// @dev The parent's block number + BLOCK_INTERVAL = this proposal's block number. + uint256 public immutable BLOCK_INTERVAL; + + /// @notice The block interval for intermediate proposals. + /// @dev BLOCK_INTERVAL must be divisible by INTERMEDIATE_BLOCK_INTERVAL. + uint256 public immutable INTERMEDIATE_BLOCK_INTERVAL; + + /// @notice The size of the initialize call data. + uint256 internal immutable INITIALIZE_CALLDATA_SIZE; + + /// @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 // + //////////////////////////////////////////////////////////////// + /// @notice The starting timestamp of the game. + Timestamp public createdAt; + + /// @notice The timestamp of the game's global resolution. + Timestamp public resolvedAt; + + /// @notice The current status of the game. + GameStatus public status; + + /// @notice Flag for the `initialize` function to prevent re-initialization. + bool internal initialized; + + /// @notice A boolean for whether or not the game type was respected when the game was created. + bool public wasRespectedGameTypeWhenCreated; + + /// @notice The starting output root of the game that is proven from in case of a challenge. + /// @dev This should match the claim root of the parent game. + Proposal public startingOutputRoot; + + /// @notice The address that can claim the bond. + address public bondRecipient; + + /// @notice Whether or not the bond has been unlocked. + bool public bondUnlocked; + + /// @notice Whether or not the bond has been claimed. + bool public bondClaimed; + + /// @notice The amount of the bond. + uint256 public bondAmount; + + /// @notice The address of the game that countered this game. + address public counteredByGameAddress; + + /// @notice The address that provided a proof of the given type. + mapping(ProofType => address) internal proofTypeToProver; + + /// @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 // + //////////////////////////////////////////////////////////////// + + /// @notice Emitted when the game is resolved. + /// @param status The status of the game. + event Resolved(GameStatus status); + + /// @notice Emitted when a proposal with a TEE proof is challenged with a ZK proof. + /// @param challenger The address of the challenger. + /// @param game The game used to challenge this proposal. + event Challenged(address indexed challenger, IDisputeGame game); + + /// @notice Emitted when the game is proved. + /// @param prover The address of the prover. + /// @param proofType The type of proof. + event Proved(address indexed prover, ProofType indexed proofType); + + /// @notice Emitted when the game is nullified. + /// @param nullifier The address of the nullifier. + /// @param intermediateRootIndex The index of the intermediate root. + /// @param intermediateRoot The intermediate root. + event Nullified(address indexed nullifier, uint256 intermediateRootIndex, bytes32 intermediateRoot); + + /// @notice Emitted when the credit is claimed. + /// @param recipient The address of the recipient. + /// @param amount The amount of credit claimed. + event CreditClaimed(address indexed recipient, uint256 amount); + + //////////////////////////////////////////////////////////////// + // Errors // + //////////////////////////////////////////////////////////////// + /// @notice When the block interval or intermediate block interval is invalid. + error InvalidBlockInterval(uint256 blockInterval, uint256 intermediateBlockInterval); + + /// @notice When the block number is unexpected. + error UnexpectedBlockNumber(uint256 expectedBlockNumber, uint256 actualBlockNumber); + + /// @notice When the game is over. + error GameOver(); + + /// @notice When the game is not over. + error GameNotOver(); + + /// @notice When the game is invalid. + error InvalidGame(); + + /// @notice When the parent game is invalid. + error InvalidParentGame(); + + /// @notice When the parent game has not resolved. + error ParentGameNotResolved(); + + /// @notice When there is no proof of the given type. + error MissingProof(ProofType proofType); + + /// @notice When the proof has already been verified. + error AlreadyProven(ProofType proofType); + + /// @notice When the proof is invalid. + error InvalidProof(); + + /// @notice When an invalid proof type is provided. + error InvalidProofType(); + + /// @notice When no proof was provided. + error NoProofProvided(); + + /// @notice When the countered by game is invalid. + error InvalidCounteredByGame(); + + /// @notice When the countered by game is not resolved. + error CounteredByGameNotResolved(); + + /// @notice When the bond recipient is empty. + error BondRecipientEmpty(); + + /// @notice When the intermediate root index is invalid. + error InvalidIntermediateRootIndex(); + + /// @notice When the intermediate root is the same as the proposed intermediate root. + error IntermediateRootSameAsProposed(); + + /// @notice When the intermediate root does not match the claim. + error IntermediateRootMismatch(bytes32 intermediateRoot, bytes32 claim); + + /// @notice Thrown when the L1 origin block is too old to verify. + error L1OriginTooOld(uint256 l1OriginNumber, uint256 currentBlock); + + /// @notice Thrown when the L1 origin block number is in the future. + error L1OriginInFuture(uint256 l1OriginNumber, uint256 currentBlock); + + /// @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. + /// @param teeVerifier The TEE verifier. + /// @param zkVerifier The ZK verifier. + /// @param teeImageHash The hash of the TEE image. + /// @param zkImageHash The hash of the ZK image. + /// @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_, + IDelayedWETH delayedWETH, + IVerifier teeVerifier, + IVerifier zkVerifier, + bytes32 teeImageHash, + bytes32 zkImageHash, + bytes32 configHash, + uint256 l2ChainId, + uint256 blockInterval, + 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_; + DISPUTE_GAME_FACTORY = ANCHOR_STATE_REGISTRY.disputeGameFactory(); + DELAYED_WETH = delayedWETH; + TEE_VERIFIER = teeVerifier; + ZK_VERIFIER = zkVerifier; + TEE_IMAGE_HASH = teeImageHash; + ZK_IMAGE_HASH = zkImageHash; + CONFIG_HASH = configHash; + L2_CHAIN_ID = l2ChainId; + BLOCK_INTERVAL = blockInterval; + INTERMEDIATE_BLOCK_INTERVAL = intermediateBlockInterval; + PROOF_THRESHOLD = proofThreshold; + + INITIALIZE_CALLDATA_SIZE = 0x7E + 0x20 * intermediateOutputRootsCount(); + } + + /// @notice Initializes the contract. + /// @param proof The proof. + /// @dev This function may only be called once. + /// @dev First byte of the proof is the proof type. + function initializeWithInitData(bytes calldata proof) external payable virtual { + // The game must not have already been initialized. + if (initialized) revert AlreadyInitialized(); + + // Revert if the calldata size is not the expected length. + // + // This is to prevent adding extra or omitting bytes from to `extraData` that result in a different game UUID + // in the factory, but are not used by the game, which would allow for multiple dispute games for the same + // output proposal to be created. + // + // Expected length: 0x7E + // - 0x04 selector + // - 0x14 creator address + // - 0x20 root claim + // - 0x20 l1 head + // - 0x20 extraData (l2BlockNumber) + // - 0x04 extraData (parentIndex) + // - 0x20 x (BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL) extraData (intermediate roots) + // - 0x02 CWIA bytes + + // - 0x20 proof length location + // - 0x20 proof length + // - ((proof.length + 32 - 1)/ 32) * 32 (round up to the nearest 32 bytes) + uint256 proofLength = (proof.length + 32 - 1) / 32 * 32; + uint256 expectedCallDataSize = INITIALIZE_CALLDATA_SIZE + 0x40 + proofLength; + assembly { + if iszero(eq(calldatasize(), expectedCallDataSize)) { + // Store the selector for `BadExtraData()` & revert. + mstore(0x00, 0x9824bdab) + revert(0x1C, 0x04) + } + } + + // Last intermediate root has to match the proposal's claim + if (intermediateOutputRoot(intermediateOutputRootsCount() - 1) != rootClaim().raw()) { + revert IntermediateRootMismatch( + intermediateOutputRoot(intermediateOutputRootsCount() - 1), rootClaim().raw() + ); + } + + // The first game is initialized with a parent index of uint32.max. + if (parentIndex() != type(uint32).max) { + // For subsequent games, get the parent game's information. + (,, IDisputeGame parentGame) = DISPUTE_GAME_FACTORY.gameAtIndex(parentIndex()); + + // Parent game must be respected, not blacklisted, not retired, and not challenged. + if (!_isValidGame(parentGame)) revert InvalidParentGame(); + + startingOutputRoot = Proposal({ + l2SequenceNumber: parentGame.l2SequenceNumber(), root: Hash.wrap(parentGame.rootClaim().raw()) + }); + } else { + // When there is no parent game, the starting output root is the anchor state for the game type. + (startingOutputRoot.root, startingOutputRoot.l2SequenceNumber) = ANCHOR_STATE_REGISTRY.getAnchorRoot(); + } + + // The block number must be BLOCK_INTERVAL blocks after the starting block number. + if (l2SequenceNumber() != startingOutputRoot.l2SequenceNumber + BLOCK_INTERVAL) { + revert UnexpectedBlockNumber(startingOutputRoot.l2SequenceNumber + BLOCK_INTERVAL, l2SequenceNumber()); + } + + // Set the game as initialized. + initialized = true; + + // Set the game's starting timestamp. + createdAt = Timestamp.wrap(uint64(block.timestamp)); + + // Set the game as respected if the game type is respected. + wasRespectedGameTypeWhenCreated = + GameType.unwrap(ANCHOR_STATE_REGISTRY.respectedGameType()) == GameType.unwrap(GAME_TYPE); + + // Set expected resolution. + expectedResolution = Timestamp.wrap(type(uint64).max); + + // Verify the proof. + ProofType proofType = ProofType(uint8(proof[0])); + + bytes32 l1OriginHash = bytes32(proof[1:33]); + uint256 l1OriginNumber = uint256(bytes32(proof[33:65])); + // Verify claimed L1 origin hash matches actual blockhash + _verifyL1Origin(l1OriginHash, l1OriginNumber); + + _verifyProof( + proof[65:], + proofType, + gameCreator(), + l1OriginHash, + startingOutputRoot.root.raw(), + startingOutputRoot.l2SequenceNumber, + rootClaim().raw(), + l2SequenceNumber(), + intermediateOutputRoots() + ); + + _updateProvingData(proofType, gameCreator()); + + emit Proved(gameCreator(), proofType); + + // Deposit the bond. + bondAmount = msg.value; + DELAYED_WETH.deposit{ value: msg.value }(); + } + + /// @notice Verifies a proof for the current game. + /// @param proofBytes The proof. + /// @dev The first byte of the proof is the proof type. + function verifyProposalProof(bytes calldata proofBytes) external { + // The game must be in progress. + if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); + + // The game must not be over. + if (gameOver()) revert GameOver(); + + ProofType proofType = ProofType(uint8(proofBytes[0])); + if (proofTypeToProver[proofType] != address(0)) revert AlreadyProven(proofType); + + _verifyProof( + proofBytes[1:], + proofType, + msg.sender, + l1Head().raw(), + startingOutputRoot.root.raw(), + startingOutputRoot.l2SequenceNumber, + rootClaim().raw(), + l2SequenceNumber(), + intermediateOutputRoots() + ); + _updateProvingData(proofType, msg.sender); + + emit Proved(msg.sender, proofType); + } + + /// @notice Resolves the game after a proof has been provided and enough time has passed. + function resolve() external returns (GameStatus) { + // The game must be in progress. + if (status != GameStatus.IN_PROGRESS) revert ClaimAlreadyResolved(); + + GameStatus parentGameStatus = _getParentGameStatus(); + // The parent game must have resolved. + if (parentGameStatus == GameStatus.IN_PROGRESS) revert ParentGameNotResolved(); + + // If the parent game's claim is invalid, blacklisted, or retired, then the current game's claim is invalid. + if (parentGameStatus == GameStatus.CHALLENGER_WINS) { + status = GameStatus.CHALLENGER_WINS; + } else { + // Game must be completed with a valid proof. + if (!gameOver()) revert GameNotOver(); + 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. + resolvedAt = Timestamp.wrap(uint64(block.timestamp)); + emit Resolved(status); + + return status; + } + + /// @notice Challenges the TEE proof with a ZK proof. + /// @param gameIndex The index of the game used to challenge. + /// @dev The game used to challenge must have a ZK proof for the same + /// block number but a different root claim as the current game. + function challenge(uint256 gameIndex) external { + // Can only challenge a game that has not been challenged or resolved yet. + if (status != GameStatus.IN_PROGRESS) revert ClaimAlreadyResolved(); + + // This game cannot be blacklisted or retired. + if (!_isValidGame(IDisputeGame(address(this)))) revert InvalidGame(); + + // The parent game cannot have been challenged. + if (_getParentGameStatus() == GameStatus.CHALLENGER_WINS) revert InvalidParentGame(); + + // The TEE prover must not be empty. + // You should nullify the game if a ZK proof has already been provided. + 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. + if (!_isValidChallengingGame(game)) revert InvalidGame(); + + AggregateVerifier challengingGame = AggregateVerifier(address(game)); + + // The ZK prover must not be empty. + if (challengingGame.zkProver() == address(0)) revert MissingProof(ProofType.ZK); + + // Update the counteredBy address. + counteredByGameAddress = address(challengingGame); + + // 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(); + + // Emit the challenged event. + emit Challenged(challengingGame.zkProver(), game); + } + + /// @notice Nullifies the game if a soundness issue is found. + /// @param proofBytes The proof. + /// @param intermediateRootIndex Index of the intermediate root to challenge. + /// @param intermediateRootToProve The intermediate root that the proof claims to be correct. + /// @dev The first byte of the proof is the proof type. + function nullify( + bytes calldata proofBytes, + uint256 intermediateRootIndex, + bytes32 intermediateRootToProve + ) + external + { + if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); + + if (intermediateRootIndex >= intermediateOutputRootsCount()) revert InvalidIntermediateRootIndex(); + + bytes32 proposedIntermediateRoot = intermediateOutputRoot(intermediateRootIndex); + if (proposedIntermediateRoot == intermediateRootToProve) revert IntermediateRootSameAsProposed(); + + ProofType proofType = ProofType(uint8(proofBytes[0])); + + if (proofTypeToProver[proofType] == address(0)) revert MissingProof(proofType); + + bytes32 startingRoot = intermediateRootIndex == 0 + ? startingOutputRoot.root.raw() + : intermediateOutputRoot(intermediateRootIndex - 1); + uint256 startingL2SequenceNumber = + startingOutputRoot.l2SequenceNumber + intermediateRootIndex * INTERMEDIATE_BLOCK_INTERVAL; + uint256 endingL2SequenceNumber = startingL2SequenceNumber + INTERMEDIATE_BLOCK_INTERVAL; + + _verifyProof( + proofBytes[1:], + proofType, + msg.sender, + l1Head().raw(), + startingRoot, + startingL2SequenceNumber, + intermediateRootToProve, + endingL2SequenceNumber, + abi.encodePacked(intermediateRootToProve) + ); + + 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); + } + + /// @notice Claim the credit belonging to the bond recipient. Reverts if the game isn't + /// finalized or if the bond transfer fails. + function claimCredit() external nonReentrant { + // The bond must not have been claimed yet. + if (bondClaimed) revert NoCreditToClaim(); + + // The bond recipient must not be empty. + if (bondRecipient == address(0)) revert BondRecipientEmpty(); + + // If this game was challenged, the countered by game must be valid or else the bond is refunded. + if (counteredByGameAddress != address(0)) { + GameStatus counteredByGameStatus = IDisputeGame(counteredByGameAddress).status(); + if (counteredByGameStatus == GameStatus.IN_PROGRESS) { + revert CounteredByGameNotResolved(); + } + // If the countered by game is invalid or not resolved, the bond is refunded. + if (!_isValidChallengingGame(IDisputeGame(counteredByGameAddress))) { + bondRecipient = gameCreator(); + } + } + + if (!bondUnlocked) { + DELAYED_WETH.unlock(bondRecipient, bondAmount); + bondUnlocked = true; + return; + } + + bondClaimed = true; + // This can fail if this game was challenged and the countered by game is + // blacklisted/retired after it resolved to DEFENDER_WINS. + // The centralized functions in DELAYED_WETH will handle this as it's a already + // a very centralized action to blacklist/retire a valid challenging game. + DELAYED_WETH.withdraw(bondRecipient, bondAmount); + + // Transfer the credit to the bond recipient. + (bool success,) = bondRecipient.call{ value: bondAmount }(hex""); + if (!success) revert BondTransferFailed(); + + // Emit the credit claimed event. + emit CreditClaimed(bondRecipient, bondAmount); + } + + /// @notice Closes the game by trying to update the anchor state. + function closeGame() external { + // We won't close the game if the system is currently paused. + if (ANCHOR_STATE_REGISTRY.paused()) { + revert GamePaused(); + } + + // Make sure that the game is resolved. + // AnchorStateRegistry should be checking this but we're being defensive here. + if (resolvedAt.raw() == 0) { + revert GameNotResolved(); + } + + // Game must be finalized according to the AnchorStateRegistry. + bool finalized = ANCHOR_STATE_REGISTRY.isGameFinalized(IDisputeGame(address(this))); + if (!finalized) { + revert GameNotFinalized(); + } + + // Try to update the anchor game first. Won't always succeed because delays can lead + // to situations in which this game might not be eligible to be a new anchor game. + // eip150-safe + try ANCHOR_STATE_REGISTRY.setAnchorState(IDisputeGame(address(this))) { } catch { } + } + + /// @notice The starting block number of the game. + function startingBlockNumber() external view returns (uint256) { + return startingOutputRoot.l2SequenceNumber; + } + + /// @notice The starting output root of the game. + function startingRootHash() external view returns (Hash) { + return startingOutputRoot.root; + } + + /// @notice A compliant implementation of this interface should return the components of the + /// game UUID's preimage provided in the cwia payload. The preimage of the UUID is + /// constructed as `keccak256(gameType . rootClaim . extraData)` where `.` denotes + /// concatenation. + /// @return gameType_ The type of proof system being used. + /// @return rootClaim_ The root claim of the DisputeGame. + /// @return extraData_ Any extra data supplied to the dispute game contract by the creator. + function gameData() external view returns (GameType, Claim, bytes memory) { + return (GAME_TYPE, rootClaim(), extraData()); + } + + /// @notice Address that provided a TEE proof. + function teeProver() external view returns (address) { + return proofTypeToProver[ProofType.TEE]; + } + + /// @notice Address that provided a ZK proof. + function zkProver() external view returns (address) { + return proofTypeToProver[ProofType.ZK]; + } + + /// @notice The game type. + /// @dev For compliance with the IDisputeGame interface. + function gameType() external view returns (GameType) { + return GAME_TYPE; + } + + /// @notice The anchor state registry. + /// @dev Needed for anchorStateRegistry.isGameRegistered() + function anchorStateRegistry() external view returns (IAnchorStateRegistry) { + return ANCHOR_STATE_REGISTRY; + } + + /// @notice Determines if the game is finished. + function gameOver() public view returns (bool) { + return expectedResolution.raw() <= block.timestamp; + } + + /// @notice The number of intermediate output roots. + /// @dev At least one as the proposal's root claim is considered an intermediate root. + function intermediateOutputRootsCount() public view returns (uint256) { + return (BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL); + } + + /// @notice The intermediate output roots of the game. + function intermediateOutputRoots() public view returns (bytes memory) { + return _getArgBytes(0x78, 0x20 * intermediateOutputRootsCount()); + } + + /// @notice The intermediate output root at the given index. + /// @param index The index of the intermediate output root. + function intermediateOutputRoot(uint256 index) public view returns (bytes32) { + if (index >= intermediateOutputRootsCount()) revert InvalidIntermediateRootIndex(); + return _getArgBytes32(0x78 + 0x20 * index); + } + + /// @notice Getter for the extra data. + function extraData() public view returns (bytes memory) { + // The extra data starts at the second word within the cwia calldata and + // is 36 + 32 x intermediateRootsCount() bytes long. + // 32 bytes are for the l2BlockNumber + // 4 bytes are for the parentIndex + // 32 bytes are for each intermediate root + return _getArgBytes(0x54, 0x24 + 0x20 * intermediateOutputRootsCount()); + } + + /// @notice Getter for the creator of the dispute game. + function gameCreator() public pure returns (address) { + return _getArgAddress(0x00); + } + + /// @notice Getter for the root claim. + function rootClaim() public pure returns (Claim) { + return Claim.wrap(_getArgBytes32(0x14)); + } + + /// @notice Getter for the parent hash of the L1 block when the dispute game was created. + function l1Head() public pure returns (Hash) { + return Hash.wrap(_getArgBytes32(0x34)); + } + + /// @notice The L2 sequence number for which this game is proposing an output root (in this case - the block + /// number). + function l2SequenceNumber() public pure returns (uint256) { + return _getArgUint256(0x54); + } + + /// @notice The parent index of the game. + function parentIndex() public pure returns (uint32) { + return _getArgUint32(0x74); + } + + /// @notice Updates the expected resolution timestamp. + function _updateExpectedResolution() internal { + uint64 delay; + + 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 newResolution = uint64(block.timestamp) + delay; + expectedResolution = Timestamp.wrap(uint64(FixedPointMathLib.min(newResolution, expectedResolution.raw()))); + } + + function _updateProvingData(ProofType proofType, address prover) internal { + proofTypeToProver[proofType] = prover; + + // Bond can be reclaimed after a ZK proof is provided. + if (proofType == ProofType.ZK) { + bondRecipient = gameCreator(); + } + + proofCount += 1; + + _updateExpectedResolution(); + } + + function _verifyProof( + bytes calldata proofBytes, + ProofType proofType, + address prover, + bytes32 l1OriginHash, + bytes32 startingRoot, + uint256 startingL2SequenceNumber, + bytes32 endingRoot, + uint256 endingL2SequenceNumber, + bytes memory intermediateRoots + ) + internal + view + { + if (proofBytes.length < 1) revert InvalidProof(); + + if (proofType == ProofType.TEE) { + _verifyTeeProof( + proofBytes, + prover, + l1OriginHash, + startingRoot, + startingL2SequenceNumber, + endingRoot, + endingL2SequenceNumber, + intermediateRoots + ); + } else if (proofType == ProofType.ZK) { + _verifyZkProof( + proofBytes, + prover, + l1OriginHash, + startingRoot, + startingL2SequenceNumber, + endingRoot, + endingL2SequenceNumber, + intermediateRoots + ); + } else { + revert InvalidProofType(); + } + } + + /// @notice Verifies a TEE proof for the current game. + /// @param proofBytes The proof: signature(65). + function _verifyTeeProof( + bytes calldata proofBytes, + address prover, + bytes32 l1OriginHash, + bytes32 startingRoot, + uint256 startingL2SequenceNumber, + bytes32 endingRoot, + uint256 endingL2SequenceNumber, + bytes memory intermediateRoots + ) + internal + view + { + bytes32 journal = keccak256( + abi.encodePacked( + prover, + l1OriginHash, + startingRoot, + startingL2SequenceNumber, + endingRoot, + endingL2SequenceNumber, + intermediateRoots, + CONFIG_HASH, + TEE_IMAGE_HASH + ) + ); + + // Validate the proof. + bytes memory proof = abi.encodePacked(prover, proofBytes); + if (!TEE_VERIFIER.verify(proof, TEE_IMAGE_HASH, journal)) revert InvalidProof(); + } + + /// @notice Verifies a ZK proof for the current game. + /// @param proofBytes The proof: zkProof (variable). + function _verifyZkProof( + bytes calldata proofBytes, + address prover, + bytes32 l1OriginHash, + bytes32 startingRoot, + uint256 startingL2SequenceNumber, + bytes32 endingRoot, + uint256 endingL2SequenceNumber, + bytes memory intermediateRoots + ) + internal + view + { + bytes32 journal = keccak256( + abi.encodePacked( + prover, + l1OriginHash, + startingRoot, + startingL2SequenceNumber, + endingRoot, + endingL2SequenceNumber, + intermediateRoots, + CONFIG_HASH, + ZK_IMAGE_HASH + ) + ); + + // Validate the proof. + if (!ZK_VERIFIER.verify(proofBytes, ZK_IMAGE_HASH, journal)) revert InvalidProof(); + } + + /// @notice Returns the status of the parent game. + /// @dev If the parent game index is `uint32.max`, then the parent game's status is considered as `DEFENDER_WINS`. + function _getParentGameStatus() internal view returns (GameStatus) { + if (parentIndex() != type(uint32).max) { + (,, IDisputeGame parentGame) = DISPUTE_GAME_FACTORY.gameAtIndex(parentIndex()); + if (ANCHOR_STATE_REGISTRY.isGameBlacklisted(parentGame) || ANCHOR_STATE_REGISTRY.isGameRetired(parentGame)) + { + return GameStatus.CHALLENGER_WINS; + } + return parentGame.status(); + } + // If this is the first dispute game (i.e. parent game index is `uint32.max`), then the + // parent game's status is considered as `DEFENDER_WINS`. + return GameStatus.DEFENDER_WINS; + } + + /// @notice Checks if the game is respected, not blacklisted, and not retired. + /// @param game The game to check. + function _isValidGame(IDisputeGame game) internal view returns (bool) { + return ANCHOR_STATE_REGISTRY.isGameRespected(game) && !ANCHOR_STATE_REGISTRY.isGameBlacklisted(game) + && !ANCHOR_STATE_REGISTRY.isGameRetired(game) && (game.status() != GameStatus.CHALLENGER_WINS); + } + + /// @notice Checks if the game is a valid game used to challenge or nullify. + /// @param game The game to check. + function _isValidChallengingGame(IDisputeGame game) internal view returns (bool) { + return + // The game type must be the same. + game.gameType().raw() == GAME_TYPE.raw() && + // The parent game must be the same. + AggregateVerifier(address(game)).parentIndex() == parentIndex() && + // The block number must be the same. + game.l2SequenceNumber() == l2SequenceNumber() && + // The root claim must be different. + game.rootClaim().raw() != rootClaim().raw() && + // The game must be valid. + _isValidGame(game); + } + + /// @notice Verifies that the claimed L1 origin hash matches the actual blockhash. + /// @param l1OriginHash The L1 block hash claimed in the proof. + /// @param l1OriginNumber The L1 block number claimed in the proof. + function _verifyL1Origin(bytes32 l1OriginHash, uint256 l1OriginNumber) internal view { + // Check for future block + if (l1OriginNumber >= block.number) { + revert L1OriginInFuture(l1OriginNumber, block.number); + } + + bytes32 actualHash; + uint256 blockAge = block.number - l1OriginNumber; + + // Prefer blockhash() over EIP-2935 when possible since it's cheaper (no external call). + if (blockAge <= BLOCKHASH_WINDOW) { + actualHash = blockhash(l1OriginNumber); + } else if (blockAge <= EIP2935_WINDOW) { + // EIP-2935 expects raw calldata: exactly 32 bytes containing the block number. + // Using a Solidity interface would add a 4-byte function selector, causing a revert. + // We use a low-level staticcall with raw 32-byte calldata instead. + (bool success, bytes memory result) = EIP2935_CONTRACT.staticcall(abi.encode(l1OriginNumber)); + if (!success || result.length != 32) { + revert L1OriginTooOld(l1OriginNumber, block.number); + } + actualHash = abi.decode(result, (bytes32)); + } else { + revert L1OriginTooOld(l1OriginNumber, block.number); + } + + if (actualHash == bytes32(0)) { + revert L1OriginTooOld(l1OriginNumber, block.number); + } + + if (actualHash != l1OriginHash) { + 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/MockDevSystemConfigGlobal.sol b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol new file mode 100644 index 000000000..dfd61fa55 --- /dev/null +++ b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { + INitroEnclaveVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; + +import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; + +/// @title DevSystemConfigGlobal +/// @notice Development version of SystemConfigGlobal with bypassed attestation for testing. +/// @dev This contract adds addDevSigner() which bypasses AWS Nitro attestation verification. +/// DO NOT deploy this contract to production networks. +contract DevSystemConfigGlobal is SystemConfigGlobal { + constructor(INitroEnclaveVerifier nitroVerifier) SystemConfigGlobal(nitroVerifier) { } + + /// @notice Registers a signer for testing (bypasses attestation verification). + /// @dev Only callable by owner. For development/testing use only. + /// @param signer The address of the signer to register. + /// @param pcr0Hash The PCR0 hash to associate with this signer. + function addDevSigner(address signer, bytes32 pcr0Hash) external onlyOwner { + signerPCR0[signer] = pcr0Hash; + emit SignerRegistered(signer, pcr0Hash); + } +} diff --git a/src/multiproof/mocks/MockSystemConfig.sol b/src/multiproof/mocks/MockSystemConfig.sol new file mode 100644 index 000000000..5182c4c0f --- /dev/null +++ b/src/multiproof/mocks/MockSystemConfig.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +contract MockSystemConfig { + address public guardian; + + constructor() { + guardian = msg.sender; + } + + function paused() public pure returns (bool) { + return false; + } +} diff --git a/src/multiproof/mocks/MockVerifier.sol b/src/multiproof/mocks/MockVerifier.sol new file mode 100644 index 000000000..fff83d15d --- /dev/null +++ b/src/multiproof/mocks/MockVerifier.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; + +contract MockVerifier is IVerifier { + function verify(bytes calldata, bytes32, bytes32) external pure returns (bool) { + return true; + } +} diff --git a/src/multiproof/tee/SystemConfigGlobal.sol b/src/multiproof/tee/SystemConfigGlobal.sol new file mode 100644 index 000000000..3cce9895f --- /dev/null +++ b/src/multiproof/tee/SystemConfigGlobal.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +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 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, ISemver { + /// @notice Maximum age of an attestation document (60 minutes), in seconds. + uint256 public constant MAX_AGE = 60 minutes; + + /// @notice Conversion factor from milliseconds to seconds. + /// @dev AWS Nitro attestation timestamps are in milliseconds since epoch, + /// 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. + mapping(address => bytes32) public signerPCR0; + + /// @notice Mapping of whether an address is a valid proposer. + mapping(address => bool) public isValidProposer; + + /// @notice Emitted when a signer is registered. + event SignerRegistered(address indexed signer, bytes32 indexed pcr0); + + /// @notice Emitted when a signer is deregistered. + event SignerDeregistered(address indexed signer); + + /// @notice Emitted when a PCR0 is registered. + event PCR0Registered(bytes32 indexed pcr0Hash); + + /// @notice Emitted when a PCR0 is deregistered. + event PCR0Deregistered(bytes32 indexed pcr0Hash); + + /// @notice Emitted when the proposer is set. + event ProposerSet(address indexed proposer, bool isValid); + + /// @notice Thrown when the PCR0 in the attestation is not registered as valid. + error InvalidPCR0(); + + /// @notice Thrown when the attestation document is too old. + error AttestationTooOld(); + + /// @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) }); + } + + /// @notice Sets the proposer address. + /// @param proposer The proposer address. + /// @param isValid Whether the proposer is valid. + function setProposer(address proposer, bool isValid) external onlyOwner { + isValidProposer[proposer] = isValid; + emit ProposerSet(proposer, isValid); + } + + /// @notice Registers a PCR0 (enclave image hash) as valid. + /// @param pcr0 The raw PCR0 bytes from the enclave. + function registerPCR0(bytes calldata pcr0) external onlyOwner { + bytes32 pcr0Hash = keccak256(pcr0); + validPCR0s[pcr0Hash] = true; + emit PCR0Registered(pcr0Hash); + } + + /// @notice Deregisters a PCR0 (enclave image hash). + /// @param pcr0 The raw PCR0 bytes from the enclave. + function deregisterPCR0(bytes calldata pcr0) external onlyOwner { + bytes32 pcr0Hash = keccak256(pcr0); + delete validPCR0s[pcr0Hash]; + emit PCR0Deregistered(pcr0Hash); + } + + /// @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(); + + // 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))); + + signerPCR0[enclaveAddress] = pcr0Hash; + emit SignerRegistered(enclaveAddress, pcr0Hash); + } + + /// @notice Deregisters a signer. + /// @param signer The address of the signer to deregister. + function deregisterSigner(address signer) external onlyOwnerOrManager { + delete signerPCR0[signer]; + emit SignerDeregistered(signer); + } + + /// @notice Checks if an address is a valid signer. + /// @param signer The address to check. + /// @return True if the signer is registered, false otherwise. + function isValidSigner(address signer) external view returns (bool) { + return signerPCR0[signer] != bytes32(0); + } + + /// @notice Initializes the contract with owner and manager. + /// @param initialOwner The initial owner address. + /// @param initialManager The initial manager address. + function initialize(address initialOwner, address initialManager) public initializer { + __OwnableManaged_init(); + transferOwnership(initialOwner); + transferManagement(initialManager); + } + + /// @notice Semantic version. + /// @custom:semver 0.1.0 + 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 new file mode 100644 index 000000000..5bbf4e90c --- /dev/null +++ b/src/multiproof/tee/TEEVerifier.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: MIT +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"; + +/// @title TEEVerifier +/// @notice Stateless TEE proof verifier that validates signatures against registered signers. +/// @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. +/// 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; + + /// @notice Thrown when the recovered signer is not a valid registered signer. + error InvalidSigner(address signer); + + /// @notice Thrown when the signature format is invalid. + error InvalidSignature(); + + /// @notice Thrown when the signer's registered PCR0 does not match the claimed imageId. + error ImageIdMismatch(bytes32 signerPCR0, bytes32 claimedImageId); + + /// @notice Thrown when the proof format is invalid. + error InvalidProofFormat(); + + /// @notice Thrown when the proposer is not a valid registered proposer. + error InvalidProposer(address proposer); + + /// @notice Constructs the TEEVerifier contract. + /// @param systemConfigGlobal The SystemConfigGlobal contract address. + constructor(SystemConfigGlobal systemConfigGlobal) { + SYSTEM_CONFIG_GLOBAL = systemConfigGlobal; + } + + /// @notice Verifies a TEE proof for a state transition. + /// @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 < 85) revert InvalidProofFormat(); + + address proposer = address(bytes20(proofBytes[0:20])); + 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) + (address signer, ECDSA.RecoverError err) = ECDSA.tryRecover(journal, signature); + + if (err != ECDSA.RecoverError.NoError) { + revert InvalidSignature(); + } + + if (!SYSTEM_CONFIG_GLOBAL.isValidProposer(proposer)) { + revert InvalidProposer(proposer); + } + + // Get the PCR0 the signer was registered with + bytes32 registeredPCR0 = SYSTEM_CONFIG_GLOBAL.signerPCR0(signer); + + // Check that the signer is registered (PCR0 != 0) + if (registeredPCR0 == bytes32(0)) { + revert InvalidSigner(signer); + } + + // Check that the signer's registered PCR0 matches the claimed imageId + // This ensures the signer was running the exact enclave image specified + if (registeredPCR0 != imageId) { + revert ImageIdMismatch(registeredPCR0, imageId); + } + + 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/libraries/SemverComp.t.sol b/test/libraries/SemverComp.t.sol index b182af378..eb07ea149 100644 --- a/test/libraries/SemverComp.t.sol +++ b/test/libraries/SemverComp.t.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; // Libraries -import { JSONParserLib } from "solady/src/utils/JSONParserLib.sol"; +import { JSONParserLib } from "@solady/utils/JSONParserLib.sol"; import { SemverComp } from "src/libraries/SemverComp.sol"; /// @title SemverComp_Harness diff --git a/test/multiproof/AggregateVerifier.t.sol b/test/multiproof/AggregateVerifier.t.sol new file mode 100644 index 000000000..d7d00dff1 --- /dev/null +++ b/test/multiproof/AggregateVerifier.t.sol @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +import { BadExtraData } from "src/dispute/lib/Errors.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; +import { Claim, GameStatus, Hash, Timestamp } from "src/dispute/lib/Types.sol"; + +import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; + +import { BaseTest } from "./BaseTest.t.sol"; + +contract AggregateVerifierTest is BaseTest { + function testInitializeWithTEEProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory proof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + + assertEq(game.wasRespectedGameTypeWhenCreated(), true); + assertEq(address(game.teeProver()), TEE_PROVER); + assertEq(address(game.zkProver()), address(0)); + assertEq(uint8(game.status()), uint8(GameStatus.IN_PROGRESS)); + assertEq(game.l2SequenceNumber(), currentL2BlockNumber); + assertEq(game.rootClaim().raw(), rootClaim.raw()); + assertEq(game.parentIndex(), type(uint32).max); + assertEq(game.gameType().raw(), AGGREGATE_VERIFIER_GAME_TYPE.raw()); + assertEq(game.gameCreator(), TEE_PROVER); + assertEq( + game.extraData(), abi.encodePacked(currentL2BlockNumber, type(uint32).max, game.intermediateOutputRoots()) + ); + 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 { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory proof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _createAggregateVerifierGame(ZK_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + + assertEq(game.wasRespectedGameTypeWhenCreated(), true); + assertEq(address(game.teeProver()), address(0)); + assertEq(address(game.zkProver()), ZK_PROVER); + assertEq(uint8(game.status()), uint8(GameStatus.IN_PROGRESS)); + assertEq(game.l2SequenceNumber(), currentL2BlockNumber); + assertEq(game.rootClaim().raw(), rootClaim.raw()); + assertEq(game.parentIndex(), type(uint32).max); + assertEq(game.gameType().raw(), AGGREGATE_VERIFIER_GAME_TYPE.raw()); + assertEq(game.gameCreator(), ZK_PROVER); + assertEq( + game.extraData(), abi.encodePacked(currentL2BlockNumber, type(uint32).max, game.intermediateOutputRoots()) + ); + 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 { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + vm.deal(TEE_PROVER, INIT_BOND); + bytes memory extraData = ""; + bytes memory initData = ""; + + vm.prank(TEE_PROVER); + vm.expectRevert(BadExtraData.selector); + factory.createWithInitData{ value: INIT_BOND }(AGGREGATE_VERIFIER_GAME_TYPE, rootClaim, extraData, initData); + } + + function testUpdatingAnchorStateRegistryWithTEEProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory proof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + + // Cannot claim bond before resolving + vm.expectRevert(AggregateVerifier.BondRecipientEmpty.selector); + game.claimCredit(); + + // Resolve after 7 days + vm.warp(block.timestamp + 7 days); + game.resolve(); + assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); + + // Unlock and reclaim bond after resolving + uint256 balanceBefore = game.gameCreator().balance; + game.claimCredit(); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game.claimCredit(); + assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game)), 0); + + // Update AnchorStateRegistry + vm.warp(block.timestamp + 1); + game.closeGame(); + (Hash root, uint256 l2SequenceNumber) = anchorStateRegistry.getAnchorRoot(); + assertEq(root.raw(), rootClaim.raw()); + assertEq(l2SequenceNumber, currentL2BlockNumber); + } + + function testUpdatingAnchorStateRegistryWithZKProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory proof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _createAggregateVerifierGame(ZK_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + + // Unlock and reclaim bond after delay + uint256 balanceBefore = game.gameCreator().balance; + game.claimCredit(); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game.claimCredit(); + assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game)), 0); + + // Resolve after another 7 days + vm.warp(block.timestamp + 7 days); + game.resolve(); + assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); + + // Update AnchorStateRegistry + vm.warp(block.timestamp + 1); + game.closeGame(); + (Hash root, uint256 l2SequenceNumber) = anchorStateRegistry.getAnchorRoot(); + assertEq(root.raw(), rootClaim.raw()); + assertEq(l2SequenceNumber, currentL2BlockNumber); + } + + function testUpdatingAnchorStateRegistryWithBothProofs() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _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; + game.claimCredit(); + + // Resolve after 1 day + vm.warp(block.timestamp + 1 days); + game.resolve(); + assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); + + // Update AnchorStateRegistry + vm.warp(block.timestamp + 1); + game.closeGame(); + (Hash root, uint256 l2SequenceNumber) = anchorStateRegistry.getAnchorRoot(); + assertEq(root.raw(), rootClaim.raw()); + assertEq(l2SequenceNumber, currentL2BlockNumber); + + // Unlock and reclaim bond after delay + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game.claimCredit(); + assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game)), 0); + } + + function testProofCannotIncreaseExpectedResolution() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, teeProof); + + Timestamp originalExpectedResolution = game.expectedResolution(); + assertEq(originalExpectedResolution.raw(), block.timestamp + 7 days); + + vm.warp(block.timestamp + 7 days - 1); + // Cannot resolve yet + vm.expectRevert(AggregateVerifier.GameNotOver.selector); + game.resolve(); + + // Provide ZK proof + _provideProof(game, ZK_PROVER, zkProof); + + // Proof should not have increased expected resolution + Timestamp expectedResolution = game.expectedResolution(); + assertEq(expectedResolution.raw(), originalExpectedResolution.raw()); + + // Resolve after 1 second + vm.warp(block.timestamp + 1); + game.resolve(); + assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); + } + + function testCannotCreateSameProposal() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, teeProof); + + Hash uuid = factory.getGameUUID( + AGGREGATE_VERIFIER_GAME_TYPE, + rootClaim, + abi.encodePacked(currentL2BlockNumber, type(uint32).max, game.intermediateOutputRoots()) + ); + vm.expectRevert(abi.encodeWithSelector(IDisputeGameFactory.GameAlreadyExists.selector, uuid)); + _createAggregateVerifierGame(ZK_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, zkProof); + } + + function testVerifyFailsWithL1OriginInFuture() public { + currentL2BlockNumber += BLOCK_INTERVAL; + // Use a future block number + uint256 l1OriginNumber = block.number + 1; + bytes32 l1OriginHash = bytes32(uint256(1)); // Fake hash + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + bytes memory proofBytes = + abi.encodePacked(uint8(AggregateVerifier.ProofType.TEE), l1OriginHash, l1OriginNumber, rootClaim.raw()); + + vm.expectRevert( + abi.encodeWithSelector(AggregateVerifier.L1OriginInFuture.selector, l1OriginNumber, block.number) + ); + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proofBytes); + } + + function testVerifyFailsWithL1OriginTooOld() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // Roll forward many blocks to make old blocks unavailable + vm.roll(block.number + 300); + + // Use a block number that's too old (outside both blockhash window and EIP-2935 window) + uint256 l1OriginNumber = 1; + bytes32 l1OriginHash = bytes32(uint256(1)); // Fake hash + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + bytes memory proofBytes = + abi.encodePacked(uint8(AggregateVerifier.ProofType.TEE), l1OriginHash, l1OriginNumber, rootClaim.raw()); + + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.L1OriginTooOld.selector, l1OriginNumber, block.number)); + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proofBytes); + } + + function testVerifyFailsWithL1OriginHashMismatch() public { + currentL2BlockNumber += BLOCK_INTERVAL; + uint256 l1OriginNumber = block.number - 1; + bytes32 wrongHash = bytes32(uint256(0xdeadbeef)); // Wrong hash + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + bytes memory proofBytes = + abi.encodePacked(uint8(AggregateVerifier.ProofType.TEE), wrongHash, l1OriginNumber, rootClaim.raw()); + + bytes32 actualHash = blockhash(l1OriginNumber); + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.L1OriginHashMismatch.selector, wrongHash, actualHash)); + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proofBytes); + } + + function testVerifyWithBlockhashWindow() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // Test verification within the 256 block window + vm.roll(block.number + 100); + + // Use a block that's within the 256 block window + uint256 l1OriginNumber = block.number - 50; + bytes32 l1OriginHash = blockhash(l1OriginNumber); + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + bytes memory proofBytes = + abi.encodePacked(uint8(AggregateVerifier.ProofType.TEE), l1OriginHash, l1OriginNumber, rootClaim.raw()); + + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proofBytes); + } + + function testVerifyWithEIP2935Window() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // Roll forward past the 256 blockhash window + vm.roll(block.number + 300); + + // Use a block that's outside blockhash window but within EIP-2935 window + uint256 l1OriginNumber = block.number - 260; // 260 > 256, so blockhash() returns 0 + bytes32 expectedHash = keccak256(abi.encodePacked("mock-blockhash", l1OriginNumber)); + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber))); + + // Mock the EIP-2935 contract response + vm.mockCall( + 0x0000F90827F1C53a10cb7A02335B175320002935, // EIP-2935 contract address + abi.encode(l1OriginNumber), // raw 32-byte calldata + abi.encode(expectedHash) // returns the blockhash + ); + + bytes memory proofBytes = + abi.encodePacked(uint8(AggregateVerifier.ProofType.TEE), expectedHash, l1OriginNumber, rootClaim.raw()); + + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proofBytes); + } + + function testDeployWithInvalidBlockIntervals() public { + // Case 1: BLOCK_INTERVAL is 0 + vm.expectRevert( + abi.encodeWithSelector(AggregateVerifier.InvalidBlockInterval.selector, 0, INTERMEDIATE_BLOCK_INTERVAL) + ); + 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, + 0, + INTERMEDIATE_BLOCK_INTERVAL, + PROOF_THRESHOLD + ); + + // Case 2: INTERMEDIATE_BLOCK_INTERVAL is 0 + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.InvalidBlockInterval.selector, BLOCK_INTERVAL, 0)); + 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, + 0, + PROOF_THRESHOLD + ); + + // Case 3: BLOCK_INTERVAL is not divisible by INTERMEDIATE_BLOCK_INTERVAL + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.InvalidBlockInterval.selector, 3, 2)); + 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, + 3, + 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 new file mode 100644 index 000000000..69cd7dd72 --- /dev/null +++ b/test/multiproof/BaseTest.t.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Test } from "forge-std/Test.sol"; + +// Optimism +import { AnchorStateRegistry } from "src/dispute/AnchorStateRegistry.sol"; +import { DelayedWETH } from "src/dispute/DelayedWETH.sol"; +import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; +import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; +import { Claim, GameStatus, GameType, Hash, Proposal, Timestamp } from "src/dispute/lib/Types.sol"; + +// OpenZeppelin +import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; + +import { MockSystemConfig } from "src/multiproof/mocks/MockSystemConfig.sol"; +import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; + +contract BaseTest is Test { + // Constants + GameType public constant AGGREGATE_VERIFIER_GAME_TYPE = GameType.wrap(621); + uint256 public constant L2_CHAIN_ID = 8453; + + // MUST HAVE: BLOCK_INTERVAL % INTERMEDIATE_BLOCK_INTERVAL == 0 + uint256 public constant BLOCK_INTERVAL = 100; + uint256 public constant INTERMEDIATE_BLOCK_INTERVAL = 10; + + uint256 public constant INIT_BOND = 1 ether; + 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; + + address public immutable TEE_PROVER = makeAddr("tee-prover"); + address public immutable ZK_PROVER = makeAddr("zk-prover"); + address public immutable ATTACKER = makeAddr("attacker"); + + bytes32 public immutable TEE_IMAGE_HASH = keccak256("tee-image"); + bytes32 public immutable ZK_IMAGE_HASH = keccak256("zk-image"); + bytes32 public immutable CONFIG_HASH = keccak256("config"); + + ProxyAdmin public proxyAdmin; + MockSystemConfig public systemConfig; + + DisputeGameFactory public factory; + AnchorStateRegistry public anchorStateRegistry; + DelayedWETH public delayedWETH; + + MockVerifier public teeVerifier; + MockVerifier public zkVerifier; + + function setUp() public virtual { + _deployContractsAndProxies(); + _initializeProxies(); + + // Deploy the implementations + _deployAndSetAggregateVerifier(); + + anchorStateRegistry.setRespectedGameType(AGGREGATE_VERIFIER_GAME_TYPE); + + // Set the timestamp to after the retirement timestamp + vm.warp(block.timestamp + 1); + } + + function _deployContractsAndProxies() internal { + // Deploy the system config + systemConfig = new MockSystemConfig(); + // Deploy the relay anchor state registry + AnchorStateRegistry _anchorStateRegistry = new AnchorStateRegistry(FINALITY_DELAY); + // Deploy the delayed WETH + DelayedWETH _delayedWETH = new DelayedWETH(DELAYED_WETH_DELAY); + // Deploy the dispute game factory + DisputeGameFactory _factory = new DisputeGameFactory(); + + // Deploy proxy admin + proxyAdmin = new ProxyAdmin(address(this)); + + // Deploy proxy for anchor state registry + TransparentUpgradeableProxy anchorStateRegistryProxy = + new TransparentUpgradeableProxy(address(_anchorStateRegistry), address(proxyAdmin), ""); + anchorStateRegistry = AnchorStateRegistry(address(anchorStateRegistryProxy)); + + // Deploy proxy for factory + TransparentUpgradeableProxy factoryProxy = + new TransparentUpgradeableProxy(address(_factory), address(proxyAdmin), ""); + factory = DisputeGameFactory(address(factoryProxy)); + + // Deploy proxy for delayed WETH + TransparentUpgradeableProxy delayedWETHProxy = + new TransparentUpgradeableProxy(address(_delayedWETH), address(proxyAdmin), ""); + delayedWETH = DelayedWETH(payable(address(delayedWETHProxy))); + + // Deploy the verifiers + teeVerifier = new MockVerifier(); + zkVerifier = new MockVerifier(); + } + + function _initializeProxies() internal { + // Initialize the proxies + anchorStateRegistry.initialize( + ISystemConfig(address(systemConfig)), + IDisputeGameFactory(address(factory)), + Proposal({ + root: Hash.wrap(keccak256(abi.encode(currentL2BlockNumber))), l2SequenceNumber: currentL2BlockNumber + }), + GameType.wrap(0) + ); + factory.initialize(address(this)); + delayedWETH.initialize(ISystemConfig(address(systemConfig))); + } + + function _deployAndSetAggregateVerifier() internal { + // Deploy the dispute game relay implementation + AggregateVerifier aggregateVerifierImpl = 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, + PROOF_THRESHOLD + ); + + // Set the implementation for the aggregate verifier + factory.setImplementation(AGGREGATE_VERIFIER_GAME_TYPE, IDisputeGame(address(aggregateVerifierImpl))); + + // Set the bond amount for the aggregate verifier + factory.setInitBond(AGGREGATE_VERIFIER_GAME_TYPE, INIT_BOND); + } + + // Helper function to create a game via factory + function _createAggregateVerifierGame( + address creator, + Claim rootClaim, + uint256 l2BlockNumber, + uint32 parentIndex, + bytes memory proof + ) + internal + returns (AggregateVerifier game) + { + bytes memory intermediateRoots = + abi.encodePacked(_generateIntermediateRootsExceptLast(l2BlockNumber), rootClaim.raw()); + bytes memory extraData = abi.encodePacked(uint256(l2BlockNumber), uint32(parentIndex), intermediateRoots); + + vm.deal(creator, INIT_BOND); + vm.prank(creator); + return AggregateVerifier( + address( + factory.createWithInitData{ value: INIT_BOND }( + AGGREGATE_VERIFIER_GAME_TYPE, rootClaim, extraData, proof + ) + ) + ); + } + + function _provideProof(AggregateVerifier game, address prover, bytes memory proofBytes) internal { + vm.prank(prover); + game.verifyProposalProof(proofBytes); + } + + /// @notice Generates a properly formatted proof for testing. + /// @dev The proof format is: l1OriginHash (32) + l1OriginNumber (32) + additional data. + /// Since MockVerifier always returns true, we just need the correct structure. + /// @param salt A salt to make proofs unique. + /// @param proofType The type of proof to generate. + /// @return proof The formatted proof bytes. + function _generateProof( + bytes memory salt, + AggregateVerifier.ProofType proofType + ) + internal + view + returns (bytes memory) + { + // Use the previous block hash as l1OriginHash + bytes32 l1OriginHash = blockhash(block.number - 1); + // Use the previous block number as l1OriginNumber + uint256 l1OriginNumber = block.number - 1; + // Add some padding/signature data (65 bytes minimum for a signature) + bytes memory signature = abi.encodePacked(salt, bytes32(0), bytes32(0), uint8(27)); + + return abi.encodePacked(uint8(proofType), l1OriginHash, l1OriginNumber, signature); + } + + function _generateIntermediateRootsExceptLast(uint256 l2BlockNumber) internal pure returns (bytes memory) { + bytes memory intermediateRoots; + uint256 startingL2BlockNumber = l2BlockNumber - BLOCK_INTERVAL; + for (uint256 i = 1; i < BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL; i++) { + intermediateRoots = abi.encodePacked( + intermediateRoots, keccak256(abi.encode(startingL2BlockNumber + INTERMEDIATE_BLOCK_INTERVAL * i)) + ); + } + return intermediateRoots; + } +} diff --git a/test/multiproof/Challenge.t.sol b/test/multiproof/Challenge.t.sol new file mode 100644 index 000000000..3d0ef2f65 --- /dev/null +++ b/test/multiproof/Challenge.t.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +import { ClaimAlreadyResolved } from "src/dispute/lib/Errors.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { Claim, GameStatus, Hash } from "src/dispute/lib/Types.sol"; + +import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; + +import { BaseTest } from "./BaseTest.t.sol"; + +contract ChallengeTest is BaseTest { + function testChallengeTEEProofWithZKProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // Create first game with TEE proof + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); + + // Create second game with different root claim and ZK proof + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game2 = + _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); + + // Get game index from factory + uint256 gameIndex = factory.gameCount() - 1; + + // Challenge game1 with game2 + game1.challenge(gameIndex); + + assertEq(uint8(game1.status()), uint8(GameStatus.CHALLENGER_WINS)); + 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); + game2.resolve(); + assertEq(uint8(game2.status()), uint8(GameStatus.DEFENDER_WINS)); + assertEq(ZK_PROVER.balance, 0); + assertEq(delayedWETH.balanceOf(address(game1)), INIT_BOND); + game1.claimCredit(); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game1.claimCredit(); + assertEq(ZK_PROVER.balance, INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game1)), 0); + } + + function testChallengeFailsIfNoTEEProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // Create first game with ZK proof (no TEE proof) + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); + bytes memory zkProof1 = _generateProof("zk-proof-1", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game1 = + _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, zkProof1); + + // Create second game with different root claim and ZK proof + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk2"))); + bytes memory zkProof2 = _generateProof("zk-proof-2", AggregateVerifier.ProofType.ZK); + + _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof2); + + uint256 gameIndex = factory.gameCount() - 1; + + vm.expectRevert( + abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.TEE) + ); + game1.challenge(gameIndex); + } + + function testChallengeFailsIfDifferentParentIndex() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); + + // Create game2 with game1 as parent + uint256 game1Index = factory.gameCount() - 1; + uint256 nextBlockNumber = currentL2BlockNumber + BLOCK_INTERVAL; + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(nextBlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + // forge-lint: disable-next-line(unsafe-typecast) + _createAggregateVerifierGame(ZK_PROVER, rootClaim2, nextBlockNumber, uint32(game1Index), zkProof); + + uint256 gameIndex = factory.gameCount() - 1; + + vm.expectRevert(AggregateVerifier.InvalidGame.selector); + game1.challenge(gameIndex); + } + + function testChallengeFailsIfChallengingGameHasNoZKProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof1 = _generateProof("tee-proof-1", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _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); + + _createAggregateVerifierGame(TEE_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, teeProof2); + + uint256 gameIndex = factory.gameCount() - 1; + + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.ZK)); + game1.challenge(gameIndex); + } + + function testChallengeFailsIfGameAlreadyResolved() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); + + // Resolve game1 + vm.warp(block.timestamp + 7 days + 1); + game1.resolve(); + + // Try to challenge game1 + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); + + uint256 challengeIndex1 = factory.gameCount() - 1; + vm.expectRevert(ClaimAlreadyResolved.selector); + game1.challenge(challengeIndex1); + } + + function testChallengeFailsIfParentGameStatusIsChallenged() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + // create parent game + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory parentProof = _generateProof("parent-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier parentGame = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, parentProof); + + uint256 parentGameIndex = factory.gameCount() - 1; + currentL2BlockNumber += BLOCK_INTERVAL; + + // create child game + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory childProof = _generateProof("child-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier childGame = + // forge-lint: disable-next-line(unsafe-typecast) + _createAggregateVerifierGame(TEE_PROVER, rootClaim2, currentL2BlockNumber, uint32(parentGameIndex), childProof); + + // blacklist parent game + anchorStateRegistry.blacklistDisputeGame(IDisputeGame(address(parentGame))); + + // challenge child game + uint256 childGameIndex = factory.gameCount() - 1; + vm.expectRevert(AggregateVerifier.InvalidParentGame.selector); + childGame.challenge(childGameIndex); + } + + function testChallengeFailsIfGameItselfIsBlacklisted() public { + currentL2BlockNumber += BLOCK_INTERVAL; + Claim rootClaim = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory proof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game = + _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + + // blacklist game + anchorStateRegistry.blacklistDisputeGame(IDisputeGame(address(game))); + + // challenge game + uint256 gameIndex = factory.gameCount() - 1; + 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 new file mode 100644 index 000000000..9ee51c066 --- /dev/null +++ b/test/multiproof/Nullify.t.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +import { GameNotInProgress } from "src/dispute/lib/Errors.sol"; +import { Claim, GameStatus } from "src/dispute/lib/Types.sol"; + +import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; + +import { BaseTest } from "./BaseTest.t.sol"; + +contract NullifyTest is BaseTest { + function testNullifyWithTEEProof() 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()); + + 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(); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game.claimCredit(); + assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game)), 0); + } + + function testNullifyWithZKProof() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); + bytes memory zkProof1 = _generateProof("zk-proof-1", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game1 = + _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); + + game1.nullify(zkProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + + 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(); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game1.claimCredit(); + assertEq(game1.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game1)), 0); + } + + function testNullifyWithTEEProofWhenTEEAndZKProofsAreProvided() 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); + + 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 teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); + game.nullify(teeProof2, 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 { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); + + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee2"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.ZK)); + game1.nullify(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + } + + function testNullifyFailsIfGameAlreadyResolved() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof1 = _generateProof("tee-proof-1", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof1); + + // Resolve game1 + vm.warp(block.timestamp + 7 days); + game1.resolve(); + + // Try to nullify game1 + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); + + vm.expectRevert(GameNotInProgress.selector); + game1.nullify(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); + } + + function testNullifyCanOverrideChallenge() public { + currentL2BlockNumber += BLOCK_INTERVAL; + + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); + bytes memory teeProof1 = _generateProof("tee-proof-1", AggregateVerifier.ProofType.TEE); + + AggregateVerifier game1 = + _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof1); + + // Challenge game1 + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + AggregateVerifier game2 = + _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); + + uint256 challengeIndex = factory.gameCount() - 1; + game1.challenge(challengeIndex); + assertEq(game1.bondRecipient(), ZK_PROVER); + + // Nullify can override challenge + game2.nullify(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim1.raw()); + + uint256 balanceBefore = game1.gameCreator().balance; + game1.claimCredit(); + assertEq(game1.bondRecipient(), TEE_PROVER); + vm.warp(block.timestamp + DELAYED_WETH_DELAY); + game1.claimCredit(); + assertEq(game1.gameCreator().balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game1)), 0); + } +} diff --git a/test/multiproof/SystemConfigGlobal.t.sol b/test/multiproof/SystemConfigGlobal.t.sol new file mode 100644 index 000000000..10636cbfa --- /dev/null +++ b/test/multiproof/SystemConfigGlobal.t.sol @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +import { Test } from "forge-std/Test.sol"; + +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ProxyAdmin } from "src/universal/ProxyAdmin.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"; + +/// @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 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; + ProxyAdmin public proxyAdmin; + + address public owner; + address public manager; + address public unauthorized; + + bytes public constant TEST_PCR0 = hex"abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"; + bytes32 public pcr0Hash; + + // Events must be redeclared here because Solidity 0.8.15 doesn't support + // referencing events from other contracts via qualified names (requires 0.8.21+) + event SignerRegistered(address indexed signer, bytes32 indexed pcr0); + event SignerDeregistered(address indexed signer); + event PCR0Registered(bytes32 indexed pcr0Hash); + event PCR0Deregistered(bytes32 indexed pcr0Hash); + event ProposerSet(address indexed proposer, bool isValid); + + function setUp() public { + owner = makeAddr("owner"); + manager = makeAddr("manager"); + unauthorized = makeAddr("unauthorized"); + + pcr0Hash = keccak256(TEST_PCR0); + + // Deploy implementation (using DevSystemConfigGlobal for test flexibility) + // 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)); + + // Deploy proxy + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(impl), address(proxyAdmin), abi.encodeCall(SystemConfigGlobal.initialize, (owner, manager)) + ); + + systemConfigGlobal = DevSystemConfigGlobal(address(proxy)); + } + + // ============ Initialization Tests ============ + + function testInitialization() public view { + assertEq(systemConfigGlobal.owner(), owner); + assertEq(systemConfigGlobal.manager(), manager); + assertEq(systemConfigGlobal.version(), "0.1.0"); + } + + // ============ PCR0 Registration Tests ============ + + function testRegisterPCR0() public { + vm.expectEmit(true, false, false, false); + emit PCR0Registered(pcr0Hash); + + vm.prank(owner); + systemConfigGlobal.registerPCR0(TEST_PCR0); + + assertTrue(systemConfigGlobal.validPCR0s(pcr0Hash)); + } + + function testRegisterPCR0FailsIfNotOwner() public { + vm.prank(manager); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.registerPCR0(TEST_PCR0); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.registerPCR0(TEST_PCR0); + } + + function testDeregisterPCR0() public { + // First register + vm.prank(owner); + systemConfigGlobal.registerPCR0(TEST_PCR0); + assertTrue(systemConfigGlobal.validPCR0s(pcr0Hash)); + + // Then deregister + vm.expectEmit(true, false, false, false); + emit PCR0Deregistered(pcr0Hash); + + vm.prank(owner); + systemConfigGlobal.deregisterPCR0(TEST_PCR0); + + assertFalse(systemConfigGlobal.validPCR0s(pcr0Hash)); + } + + function testDeregisterPCR0FailsIfNotOwner() public { + vm.prank(owner); + systemConfigGlobal.registerPCR0(TEST_PCR0); + + vm.prank(manager); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.deregisterPCR0(TEST_PCR0); + } + + // ============ Signer Deregistration Tests ============ + + function testDeregisterSignerAsOwner() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("signer-pcr0"); + + // Add signer via DevSystemConfigGlobal + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + // Verify signer is registered + assertTrue(systemConfigGlobal.isValidSigner(signer)); + + // Deregister as owner + vm.expectEmit(true, false, false, false); + emit SignerDeregistered(signer); + + vm.prank(owner); + systemConfigGlobal.deregisterSigner(signer); + + assertFalse(systemConfigGlobal.isValidSigner(signer)); + assertEq(systemConfigGlobal.signerPCR0(signer), bytes32(0)); + } + + function testDeregisterSignerAsManager() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("signer-pcr0"); + + // Add signer via DevSystemConfigGlobal + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + assertTrue(systemConfigGlobal.isValidSigner(signer)); + + vm.prank(manager); + systemConfigGlobal.deregisterSigner(signer); + + assertFalse(systemConfigGlobal.isValidSigner(signer)); + } + + function testDeregisterSignerFailsIfUnauthorized() public { + address signer = makeAddr("signer"); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner or the manager"); + systemConfigGlobal.deregisterSigner(signer); + } + + // ============ Proposer Tests ============ + + function testSetProposer() public { + address newProposer = makeAddr("proposer"); + + vm.expectEmit(true, false, false, false); + emit ProposerSet(newProposer, true); + + vm.prank(owner); + systemConfigGlobal.setProposer(newProposer, true); + + assertTrue(systemConfigGlobal.isValidProposer(newProposer)); + } + + function testSetProposerFailsIfNotOwner() public { + address newProposer = makeAddr("proposer"); + + vm.prank(manager); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.setProposer(newProposer, true); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.setProposer(newProposer, true); + } + + // ============ isValidSigner Tests ============ + + function testIsValidSignerReturnsFalseForUnregistered() public { + address unregistered = makeAddr("unregistered"); + assertFalse(systemConfigGlobal.isValidSigner(unregistered)); + } + + function testIsValidSignerReturnsTrueForRegistered() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("signer-pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + assertTrue(systemConfigGlobal.isValidSigner(signer)); + } + + // ============ signerPCR0 Tests ============ + + function testSignerPCR0ReturnsZeroForUnregistered() public { + address unregistered = makeAddr("unregistered"); + assertEq(systemConfigGlobal.signerPCR0(unregistered), bytes32(0)); + } + + function testSignerPCR0ReturnsCorrectValue() public { + address signer = makeAddr("signer"); + bytes32 expectedPcr0 = keccak256("signer-pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, expectedPcr0); + + assertEq(systemConfigGlobal.signerPCR0(signer), expectedPcr0); + } + + // ============ MAX_AGE Tests ============ + + function testMaxAgeConstant() public view { + assertEq(systemConfigGlobal.MAX_AGE(), 60 minutes); + } + + // ============ Ownership Transfer Tests ============ + + function testTransferOwnership() public { + address newOwner = makeAddr("newOwner"); + + vm.prank(owner); + systemConfigGlobal.transferOwnership(newOwner); + + assertEq(systemConfigGlobal.owner(), newOwner); + } + + function testTransferOwnershipFailsIfNotOwner() public { + address newOwner = makeAddr("newOwner"); + + vm.prank(manager); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.transferOwnership(newOwner); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.transferOwnership(newOwner); + } + + function testTransferOwnershipFailsForZeroAddress() public { + vm.prank(owner); + vm.expectRevert("OwnableManaged: new owner is the zero address"); + systemConfigGlobal.transferOwnership(address(0)); + } + + // ============ Management Transfer Tests ============ + + function testTransferManagementAsOwner() public { + address newManager = makeAddr("newManager"); + + vm.prank(owner); + systemConfigGlobal.transferManagement(newManager); + + assertEq(systemConfigGlobal.manager(), newManager); + } + + function testTransferManagementAsManager() public { + address newManager = makeAddr("newManager"); + + vm.prank(manager); + systemConfigGlobal.transferManagement(newManager); + + assertEq(systemConfigGlobal.manager(), newManager); + } + + function testTransferManagementFailsIfUnauthorized() public { + address newManager = makeAddr("newManager"); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner or the manager"); + systemConfigGlobal.transferManagement(newManager); + } + + function testTransferManagementFailsForZeroAddress() public { + vm.prank(owner); + vm.expectRevert("OwnableManaged: new manager is the zero address"); + systemConfigGlobal.transferManagement(address(0)); + } + + // ============ Renounce Tests ============ + + function testRenounceOwnership() public { + vm.prank(owner); + systemConfigGlobal.renounceOwnership(); + + assertEq(systemConfigGlobal.owner(), address(0)); + } + + function testRenounceManagementAsOwner() public { + vm.prank(owner); + systemConfigGlobal.renounceManagement(); + + assertEq(systemConfigGlobal.manager(), address(0)); + } + + function testRenounceManagementAsManager() public { + vm.prank(manager); + systemConfigGlobal.renounceManagement(); + + assertEq(systemConfigGlobal.manager(), address(0)); + } + + // ============ DevSystemConfigGlobal: addDevSigner Tests ============ + + function testAddDevSigner() public { + address signer = makeAddr("dev-signer"); + bytes32 devPcr0Hash = keccak256("dev-pcr0"); + + vm.expectEmit(true, true, false, false); + emit SignerRegistered(signer, devPcr0Hash); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + + assertTrue(systemConfigGlobal.isValidSigner(signer)); + assertEq(systemConfigGlobal.signerPCR0(signer), devPcr0Hash); + } + + function testAddDevSignerFailsIfNotOwner() public { + address signer = makeAddr("dev-signer"); + bytes32 devPcr0Hash = keccak256("dev-pcr0"); + + vm.prank(manager); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + + vm.prank(unauthorized); + vm.expectRevert("OwnableManaged: caller is not the owner"); + systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + } + + function testAddDevSignerCanOverwriteExisting() public { + address signer = makeAddr("dev-signer"); + bytes32 firstPcr0 = keccak256("first-pcr0"); + bytes32 secondPcr0 = keccak256("second-pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, firstPcr0); + assertEq(systemConfigGlobal.signerPCR0(signer), firstPcr0); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, secondPcr0); + assertEq(systemConfigGlobal.signerPCR0(signer), secondPcr0); + } + + function testAddDevSignerWithZeroPcr0() public { + address signer = makeAddr("dev-signer"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, bytes32(0)); + + // Signer should not be valid because PCR0 is zero + assertFalse(systemConfigGlobal.isValidSigner(signer)); + assertEq(systemConfigGlobal.signerPCR0(signer), bytes32(0)); + } + + function testAddMultipleDevSigners() public { + address signer1 = makeAddr("dev-signer-1"); + address signer2 = makeAddr("dev-signer-2"); + address signer3 = makeAddr("dev-signer-3"); + + bytes32 pcr0Hash1 = keccak256("pcr0-1"); + bytes32 pcr0Hash2 = keccak256("pcr0-2"); + bytes32 pcr0Hash3 = keccak256("pcr0-3"); + + vm.startPrank(owner); + systemConfigGlobal.addDevSigner(signer1, pcr0Hash1); + systemConfigGlobal.addDevSigner(signer2, pcr0Hash2); + systemConfigGlobal.addDevSigner(signer3, pcr0Hash3); + vm.stopPrank(); + + assertTrue(systemConfigGlobal.isValidSigner(signer1)); + assertTrue(systemConfigGlobal.isValidSigner(signer2)); + assertTrue(systemConfigGlobal.isValidSigner(signer3)); + + assertEq(systemConfigGlobal.signerPCR0(signer1), pcr0Hash1); + assertEq(systemConfigGlobal.signerPCR0(signer2), pcr0Hash2); + assertEq(systemConfigGlobal.signerPCR0(signer3), pcr0Hash3); + } +} diff --git a/test/multiproof/TEEVerifier.t.sol b/test/multiproof/TEEVerifier.t.sol new file mode 100644 index 000000000..3a1095d95 --- /dev/null +++ b/test/multiproof/TEEVerifier.t.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.15; + +import { Test } from "forge-std/Test.sol"; + +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ProxyAdmin } from "src/universal/ProxyAdmin.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"; + +contract TEEVerifierTest is Test { + TEEVerifier public verifier; + DevSystemConfigGlobal public systemConfigGlobal; + ProxyAdmin public proxyAdmin; + + // Test signer - we'll derive address from private key + uint256 internal constant SIGNER_PRIVATE_KEY = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; + address internal signerAddress; + + bytes32 internal constant PCR0_HASH = keccak256("test-pcr0"); + bytes32 internal constant IMAGE_ID = PCR0_HASH; // imageId must match PCR0 hash + address internal immutable PROPOSER = makeAddr("proposer"); + + address internal owner; + + function setUp() public { + owner = address(this); + + // Derive signer address from private key + signerAddress = vm.addr(SIGNER_PRIVATE_KEY); + + // Deploy implementation (NitroEnclaveVerifier not needed for dev signer tests) + DevSystemConfigGlobal impl = new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0))); + + // Deploy proxy admin + proxyAdmin = new ProxyAdmin(address(this)); + + // Deploy proxy + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(impl), address(proxyAdmin), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + ); + + systemConfigGlobal = DevSystemConfigGlobal(address(proxy)); + + // Register the signer with PCR0 hash + systemConfigGlobal.addDevSigner(signerAddress, PCR0_HASH); + + // Set the proposer as valid + systemConfigGlobal.setProposer(PROPOSER, true); + + // Deploy TEEVerifier + verifier = new TEEVerifier(SystemConfigGlobal(address(systemConfigGlobal))); + } + + function testVerifyValidSignature() public view { + // Create a journal hash + bytes32 journal = keccak256("test-journal"); + + // 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) + signature(65) = 85 bytes + bytes memory proofBytes = abi.encodePacked(PROPOSER, signature); + + // Verify should return true + bool result = verifier.verify(proofBytes, IMAGE_ID, journal); + assertTrue(result); + } + + function testVerifyFailsWithInvalidSignature() public { + bytes32 journal = keccak256("test-journal"); + + // 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, invalidSignature); + + vm.expectRevert(TEEVerifier.InvalidSignature.selector); + verifier.verify(proofBytes, IMAGE_ID, journal); + } + + function testVerifyFailsWithInvalidProposer() public { + // Create a journal hash + bytes32 journal = keccak256("test-journal"); + + // 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) + 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); + } + + function testVerifyFailsWithUnregisteredSigner() public { + // Use a different private key that's not registered + uint256 unregisteredKey = 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef; + address unregisteredSigner = vm.addr(unregisteredKey); + + bytes32 journal = keccak256("test-journal"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(unregisteredKey, journal); + bytes memory signature = abi.encodePacked(r, s, v); + + bytes memory proofBytes = abi.encodePacked(PROPOSER, signature); + + vm.expectRevert(abi.encodeWithSelector(TEEVerifier.InvalidSigner.selector, unregisteredSigner)); + verifier.verify(proofBytes, IMAGE_ID, journal); + } + + function testVerifyFailsWithImageIdMismatch() public { + bytes32 journal = keccak256("test-journal"); + + (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, signature); + + // Use a different imageId that doesn't match the registered PCR0 + bytes32 wrongImageId = keccak256("wrong-image-id"); + + vm.expectRevert(abi.encodeWithSelector(TEEVerifier.ImageIdMismatch.selector, PCR0_HASH, wrongImageId)); + verifier.verify(proofBytes, wrongImageId, journal); + } + + function testVerifyFailsWithInvalidProofFormat() public { + bytes32 journal = keccak256("test-journal"); + + // Proof too short (less than 85 bytes) + bytes memory shortProof = new bytes(50); + + vm.expectRevert(TEEVerifier.InvalidProofFormat.selector); + verifier.verify(shortProof, IMAGE_ID, journal); + } + + function testConstants() public view { + assertEq(address(verifier.SYSTEM_CONFIG_GLOBAL()), address(systemConfigGlobal)); + } +} 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/setup/Setup.sol b/test/setup/Setup.sol index 3ffc56b06..0e9f1fe1d 100644 --- a/test/setup/Setup.sol +++ b/test/setup/Setup.sol @@ -67,6 +67,8 @@ import { INativeAssetLiquidity } from "interfaces/L2/INativeAssetLiquidity.sol"; import { IFeeSplitter } from "interfaces/L2/IFeeSplitter.sol"; import { IL1Withdrawer } from "interfaces/L2/IL1Withdrawer.sol"; import { ISuperchainRevSharesCalculator } from "interfaces/L2/ISuperchainRevSharesCalculator.sol"; +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; +import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; /// @title Setup /// @dev This contact is responsible for setting up the contracts in state. It currently @@ -156,6 +158,8 @@ abstract contract Setup is FeatureFlags { IFeeSplitter feeSplitter = IFeeSplitter(payable(Predeploys.FEE_SPLITTER)); IL1Withdrawer l1Withdrawer; ISuperchainRevSharesCalculator superchainRevSharesCalculator; + IVerifier aggregateVerifier; + SystemConfigGlobal systemConfigGlobal; /// @notice Indicates whether a test is running against a forked production network. function isForkTest() public view returns (bool) { @@ -294,6 +298,8 @@ abstract contract Setup is FeatureFlags { superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))); superchainProxyAdminOwner = superchainProxyAdmin.owner(); mips = IBigStepper(artifacts.mustGetAddress("MipsSingleton")); + aggregateVerifier = IVerifier(artifacts.mustGetAddress("AggregateVerifier")); + systemConfigGlobal = SystemConfigGlobal(artifacts.mustGetAddress("SystemConfigGlobal")); if (deploy.cfg().useAltDA()) { dataAvailabilityChallenge = diff --git a/test/vendor/Initializable.t.sol b/test/vendor/Initializable.t.sol index 1e2425daa..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,25 +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 + // 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. + + // SystemConfigGlobalImpl contracts.push( InitializeableContract({ - name: "ETHLockboxProxy", - target: address(ethLockbox), - initCalldata: abi.encodeCall( - ethLockbox.initialize, (ISystemConfig(address(0)), new IOptimismPortal2[](0)) - ) + name: "SystemConfigGlobalImpl", + target: address(systemConfigGlobal), + initCalldata: abi.encodeCall(SystemConfigGlobal.initialize, (address(0), address(0))) }) ); } @@ -368,7 +384,7 @@ contract Initializer_Test is CommonTest { function test_cannotReinitialize_succeeds() public { // Collect exclusions. uint256 j; - string[] memory excludes = new string[](14); + 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,6 +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"; + // 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); From a176098aabbe28b276702c09f5af309ccf3d8585 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Sat, 7 Mar 2026 02:41:05 +0000 Subject: [PATCH 02/18] setImplementation calls in dev deploy scripts to pass required args parameter (#202) --- scripts/multiproof/DeployDevNoNitro.s.sol | 2 +- scripts/multiproof/DeployDevWithNitro.s.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index 04f5cc9e3..2cb9cd95e 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -197,7 +197,7 @@ contract DeployDevNoNitro is Script { ); console.log("AggregateVerifier:", aggregateVerifier); - DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier), ""); DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); console.log("Registered AggregateVerifier with factory"); } diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index 875674ae3..c4c808d3a 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -232,7 +232,7 @@ contract DeployDevWithNitro is Script { ); console.log("AggregateVerifier:", aggregateVerifier); - DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier)); + DisputeGameFactory(disputeGameFactory).setImplementation(gameType, IDisputeGame(aggregateVerifier), ""); DisputeGameFactory(disputeGameFactory).setInitBond(gameType, INIT_BOND); console.log("Registered AggregateVerifier with factory"); } From 0ed5c6ebaf551f749991bc4260ac9a1dfc96aa71 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Wed, 11 Mar 2026 13:04:35 +0000 Subject: [PATCH 03/18] feat(CHAIN-3446): add signer enumeration to SystemConfigGlobal (#204) * feat(CHAIN-3446): add getRegisteredSigners() enumeration to SystemConfigGlobal * Fix fmt * Regenerate semver-lock.json --- snapshots/semver-lock.json | 8 +- .../mocks/MockDevSystemConfigGlobal.sol | 4 + src/multiproof/tee/SystemConfigGlobal.sol | 21 +++- test/multiproof/SystemConfigGlobal.t.sol | 118 +++++++++++++++++- 4 files changed, 144 insertions(+), 7 deletions(-) diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index 08bc12a07..16200188b 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -248,12 +248,12 @@ "sourceCodeHash": "0xb9786dc79b4b494d81905235f7bda044c5b1a98ad82416829f5f6948be1175cc" }, "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal": { - "initCodeHash": "0x76da4f2a736d7a39a01720e5d900a85fcaa60ba0430fcacbb8ab367f55ba5411", - "sourceCodeHash": "0xa6261402efe0105e2a4f9369818bafb4e65515e51850b44d47504151e1c39d01" + "initCodeHash": "0xee219c003a6af440b447e214e43d520e802001ae3d557262a7921ca3d57ebddf", + "sourceCodeHash": "0xe350108585e0855f10bac20d0e8894b3de9afe3be413908b4c59a1036e7a9842" }, "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal:dispute": { - "initCodeHash": "0xfae3a71157f3c64a7bda037ec116bf6e7265099397d9bcad22c01cc1f029ed7d", - "sourceCodeHash": "0xa6261402efe0105e2a4f9369818bafb4e65515e51850b44d47504151e1c39d01" + "initCodeHash": "0x8ae045f0121d2c63ab6f0a830be842aaf0445096bfabe29d85cfd9bd38b40565", + "sourceCodeHash": "0xe350108585e0855f10bac20d0e8894b3de9afe3be413908b4c59a1036e7a9842" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { "initCodeHash": "0x78317d9088a26523d938ce0d88ed0134abc60292c0cdb3f8a6a9530638fd9e9a", diff --git a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol index dfd61fa55..4dc6f7159 100644 --- a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol +++ b/src/multiproof/mocks/MockDevSystemConfigGlobal.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.15; import { INitroEnclaveVerifier } from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; @@ -12,6 +13,8 @@ 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 { + using EnumerableSetLib for EnumerableSetLib.AddressSet; + constructor(INitroEnclaveVerifier nitroVerifier) SystemConfigGlobal(nitroVerifier) { } /// @notice Registers a signer for testing (bypasses attestation verification). @@ -20,6 +23,7 @@ contract DevSystemConfigGlobal is SystemConfigGlobal { /// @param pcr0Hash The PCR0 hash to associate with this signer. function addDevSigner(address signer, bytes32 pcr0Hash) external onlyOwner { signerPCR0[signer] = pcr0Hash; + _registeredSigners.add(signer); emit SignerRegistered(signer, pcr0Hash); } } diff --git a/src/multiproof/tee/SystemConfigGlobal.sol b/src/multiproof/tee/SystemConfigGlobal.sol index 3cce9895f..c15b876ad 100644 --- a/src/multiproof/tee/SystemConfigGlobal.sol +++ b/src/multiproof/tee/SystemConfigGlobal.sol @@ -11,6 +11,7 @@ import { } 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"; +import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; /// @title SystemConfigGlobal /// @notice Manages TEE signer registration via ZK-verified AWS Nitro attestation. @@ -19,6 +20,7 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// 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, ISemver { + using EnumerableSetLib for EnumerableSetLib.AddressSet; /// @notice Maximum age of an attestation document (60 minutes), in seconds. uint256 public constant MAX_AGE = 60 minutes; @@ -41,6 +43,11 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { /// @notice Mapping of whether an address is a valid proposer. mapping(address => bool) public isValidProposer; + /// @notice Enumerable set of all currently registered signer addresses. + /// @dev Kept in sync with `signerPCR0`: add on register, remove on deregister. + /// Enables O(1) on-chain enumeration via `getRegisteredSigners()`. + EnumerableSetLib.AddressSet internal _registeredSigners; + /// @notice Emitted when a signer is registered. event SignerRegistered(address indexed signer, bytes32 indexed pcr0); @@ -128,6 +135,7 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { address enclaveAddress = address(uint160(uint256(publicKeyHash))); signerPCR0[enclaveAddress] = pcr0Hash; + _registeredSigners.add(enclaveAddress); emit SignerRegistered(enclaveAddress, pcr0Hash); } @@ -135,6 +143,7 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { /// @param signer The address of the signer to deregister. function deregisterSigner(address signer) external onlyOwnerOrManager { delete signerPCR0[signer]; + _registeredSigners.remove(signer); emit SignerDeregistered(signer); } @@ -145,6 +154,14 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { return signerPCR0[signer] != bytes32(0); } + /// @notice Returns all currently registered signer addresses. + /// @dev Reads directly from the on-chain enumerable set — no event scanning required. + /// The order of addresses in the returned array is not guaranteed. + /// @return An array of all registered signer addresses. + function getRegisteredSigners() external view returns (address[] memory) { + return _registeredSigners.values(); + } + /// @notice Initializes the contract with owner and manager. /// @param initialOwner The initial owner address. /// @param initialManager The initial manager address. @@ -155,9 +172,9 @@ contract SystemConfigGlobal is OwnableManagedUpgradeable, ISemver { } /// @notice Semantic version. - /// @custom:semver 0.1.0 + /// @custom:semver 0.2.0 function version() public pure virtual returns (string memory) { - return "0.1.0"; + return "0.2.0"; } /// @dev Finds PCR0 (index 0) in the PCR array and returns its keccak256 hash. diff --git a/test/multiproof/SystemConfigGlobal.t.sol b/test/multiproof/SystemConfigGlobal.t.sol index 10636cbfa..c57409d4b 100644 --- a/test/multiproof/SystemConfigGlobal.t.sol +++ b/test/multiproof/SystemConfigGlobal.t.sol @@ -67,7 +67,7 @@ contract SystemConfigGlobalTest is Test { function testInitialization() public view { assertEq(systemConfigGlobal.owner(), owner); assertEq(systemConfigGlobal.manager(), manager); - assertEq(systemConfigGlobal.version(), "0.1.0"); + assertEq(systemConfigGlobal.version(), "0.2.0"); } // ============ PCR0 Registration Tests ============ @@ -394,4 +394,120 @@ contract SystemConfigGlobalTest is Test { assertEq(systemConfigGlobal.signerPCR0(signer2), pcr0Hash2); assertEq(systemConfigGlobal.signerPCR0(signer3), pcr0Hash3); } + + // ============ getRegisteredSigners Tests ============ + + function testGetRegisteredSignersEmpty() public view { + address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + assertEq(signers.length, 0); + } + + function testGetRegisteredSignersAfterRegister() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + assertEq(signers.length, 1); + assertEq(signers[0], signer); + } + + function testGetRegisteredSignersAfterDeregister() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + assertEq(systemConfigGlobal.getRegisteredSigners().length, 1); + + vm.prank(owner); + systemConfigGlobal.deregisterSigner(signer); + + address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + assertEq(signers.length, 0); + } + + function testGetRegisteredSignersMultiple() public { + address signer1 = makeAddr("signer-1"); + address signer2 = makeAddr("signer-2"); + address signer3 = makeAddr("signer-3"); + + bytes32 sharedPcr0 = keccak256("pcr0"); + + vm.startPrank(owner); + systemConfigGlobal.addDevSigner(signer1, sharedPcr0); + systemConfigGlobal.addDevSigner(signer2, sharedPcr0); + systemConfigGlobal.addDevSigner(signer3, sharedPcr0); + vm.stopPrank(); + + address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + assertEq(signers.length, 3); + + // Verify all three are present (order not guaranteed) + bool foundSigner1; + bool foundSigner2; + bool foundSigner3; + for (uint256 i = 0; i < signers.length; i++) { + if (signers[i] == signer1) foundSigner1 = true; + if (signers[i] == signer2) foundSigner2 = true; + if (signers[i] == signer3) foundSigner3 = true; + } + assertTrue(foundSigner1); + assertTrue(foundSigner2); + assertTrue(foundSigner3); + } + + function testGetRegisteredSignersConsistencyAfterMixedOperations() public { + address signer1 = makeAddr("signer-1"); + address signer2 = makeAddr("signer-2"); + address signer3 = makeAddr("signer-3"); + + bytes32 sharedPcr0 = keccak256("pcr0"); + + // Register three signers + vm.startPrank(owner); + systemConfigGlobal.addDevSigner(signer1, sharedPcr0); + systemConfigGlobal.addDevSigner(signer2, sharedPcr0); + systemConfigGlobal.addDevSigner(signer3, sharedPcr0); + vm.stopPrank(); + + assertEq(systemConfigGlobal.getRegisteredSigners().length, 3); + + // Deregister the middle one + vm.prank(manager); + systemConfigGlobal.deregisterSigner(signer2); + + address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + assertEq(signers.length, 2); + + // Mapping and set stay consistent + for (uint256 i = 0; i < signers.length; i++) { + assertTrue(systemConfigGlobal.isValidSigner(signers[i])); + assertNotEq(signers[i], signer2); + } + + // Deregistered signer not in mapping either + assertFalse(systemConfigGlobal.isValidSigner(signer2)); + assertEq(systemConfigGlobal.signerPCR0(signer2), bytes32(0)); + } + + function testGetRegisteredSignersDeregisterIdempotent() public { + address signer = makeAddr("signer"); + bytes32 signerPcr0 = keccak256("pcr0"); + + vm.prank(owner); + systemConfigGlobal.addDevSigner(signer, signerPcr0); + + vm.prank(owner); + systemConfigGlobal.deregisterSigner(signer); + + // Deregistering again should not revert and set should still be empty + vm.prank(owner); + systemConfigGlobal.deregisterSigner(signer); + + assertEq(systemConfigGlobal.getRegisteredSigners().length, 0); + } } From 0e6419b69bd308a78b94107531834848d9323090 Mon Sep 17 00:00:00 2001 From: roger-bai-coinbase Date: Wed, 11 Mar 2026 10:10:08 -0400 Subject: [PATCH 04/18] Simplify and modularize aggregate verifier + verifiers (#201) * initial commit * Refactor tests and simplify verifier * Refactor proof verification methods to consolidate TEE and ZK proof handling into a single function, improving code clarity and maintainability. Update tests accordingly to reflect the new verification structure. * refactor tests and errors * Prevent proofs from extending resolution time * ZK proof allows game creator to immediately reclaim bond * Additional tests * Refactor test cases to standardize warp duration and improve naming conventions for clarity in Nullify tests. * Add validation to ensure parent game has a proof before creating a child game in AggregateVerifier. Implement corresponding test case to verify this behavior. * Use calldata and remove unused variable * Make internal verify functions consistent * fix: can claim bond after nullifying a challenge * prevent challenges if parent or game itself is invalid * Enhance AggregateVerifier to include hashes for TEE and ZK images, and rollup configuration. Update verification methods to use a journal hash instead of root claims. Modify MockVerifier and tests accordingly. * Add ReentrancyGuard to AggregateVerifier and protect claimCredit function * Add constant for initialize calldata size in AggregateVerifier and update validation check to use this constant * Add test to validate failure on invalid calldata size in AggregateVerifier * Refactor l2BlockNumber function to l2SequenceNumber in AggregateVerifier, updating documentation and logic to clarify its purpose as the L2 sequence number. * Refactor visibility of state variables in AggregateVerifier from internal to public, enhancing accessibility for contract interactions. * Moved wasRespectedGameTypeWhenCreated for storage optimization * Remove underscores from constructor variables * IDIsputeGame compliance * Remove implicit returns * Add CreditClaimed event and update claimCredit logic in AggregateVerifier to emit event upon credit transfer * Rename getParentGameStatus to _getParentGameStatus in AggregateVerifier for consistency with internal function naming conventions. * Refactor return logic in getParentGameStatus to improve clarity by consolidating the return statement for the first dispute game scenario. * solidity style guide * forge fmt * Fix tests * remove unused imports * Named imports, reorganized imports, defined errors directly * linter * Add underscores to deal with compiler warnings * Refactor and have consistent comments * Update verifier interface to include image ID * Added feature where a proof is required for initialization * Added feature where a proof is required for initialization * Add back in IDisputeGame inheritance * forge fmt * refactor proof format * game type validation on challenging game * Add delayedWETH * forge fmt * Check challenging game validity when claiming credit * Add TEEVerifier and SystemConfigGlobal contracts and update AggregateVerifier to include l1OriginNumber in journal * fix(TEEVerifier): use correct EIP-2935 address and raw calldata for blockhash lookups * Refactor TEE contracts and deployment script based on PR review feedback * Refactor TEE contracts and deployment script based on PR review feedback * Remove underscore-prefixed parameters from mock contracts per style guide * Add comprehensive tests for TEEVerifier, SystemConfigGlobal, and DevSystemConfigGlobal; fix proof format in existing tests * Update teeProposer to match proposer address * correct teeImageHash in Sepolia deploy config * Moving TEE proposer to TEEVerifier * fix TEE comment * feat: intermediate roots for nullification * move L1 origin hash check from TEEVerifier to AggregateVerifier * fix tests * forge fmt * feat: split deploy configs and scripts into no-nitro and with-nitro variants * refactor _verifyProof * added block interval tests and cleaned up some errors * forge fmt * verify proof earlier during initialize * revert last commit * refactor initialize * refactor * fix: register TEE proposer during deployment and add intermediateBlockInterval to WithNitro script * use l1head for proofs after initialization * forge fmt * Fix comments from PR feedback Co-authored-by: Leopold Joy * step 1 fix dependencies and op commit * make multiproof compatible with base contracts * fix imports in scripts * fix mocks * format and seperate out multiproof tests * add tests to just and gen semver * fix tests * rm unecessary op commit * apply optimism patch for multiproof * move multiproof tests * move files and delete multiproof test usage and profile * remove remappings of nitro and op enclave * undo multiproof changes and solady import change * support AggregateVerifier in initalizer test * fix import path * semver * semver * semver * deterministic semverlock * add comment * refactor multiproof patch changes. fix typo * semver * fmt * semver * fix tests * fix tests where bytecodes size was different * fmt * semver * semver * semver * make aggregateverifies excluded like faultdispute game. fix systemconfiggloabal initialize * fmt * fix tests * semver * rm just test-multiproof * Replace onchain Nitro cert verification with Automata ZK verifier (#197) * Replace onchain Nitro cert verification with Automata ZK verifier, add ISemver to multiproof contracts, wire SystemConfigGlobal into standard deploy pipeline * Integrate multiproof config into standard DeployConfig, fix TEEVerifier proof format to match AggregateVerifier's l1head change * Fix fmt * Replace aws-nitro-enclave-attestation submodule with no-git dependency in Makefile * Consolidate deploy configs: migrate dev scripts to standard DeployConfig, add multiproof fields to sepolia.json and hardhat.json, remove separate nitro config files * Regenerate snapshots for updated and new multiproof contracts * Fix Initializable test: guard ETHLockbox entries for non-interop deploys, exclude AggregateVerifier (uses custom bool instead of OZ _initialized) * Add test-multiproof recipe to Justfile for CI * Address PR feedback: extract GameType local var, stricter pubKey check, iterate PCRs, add nitroEnclaveVerifier to Input, revert sepolia.json owner, remove redundant CI recipe * Resolve merge conflicts and regenerate semver-lock snapshots * Regenerate semver-lock with CI profile for correct bytecode hashes * Regenerate semver-lock with all compiler profiles including dispute * Regenerate semver-lock.json to remove stale dispute profile entries * Fix misleading TEEVerifier comment, require nitroEnclaveVerifier in deploy config, and parameterize hardcoded l2ChainID/block intervals in DeployImplementations * Reset semvar versioning in SystemConfigGlobal * Regenerate semver-lock.json for SystemConfigGlobal and TEEVerifier changes * correct SystemConfigGlobal.t.sol testInitialization() test cases to check correct version() number * use a proof threshold and allow ZK proofs after TEE nullification (#199) * use a proof threshold and allow ZK proofs after TEE nullification * pr feedback * update deployment scripts and tests * allow tee nullfiication when a zk proof exists. extend timestamp in this case to allow for zk nullification * Fix stack-too-deep in DeployImplementations and regenerate semver-lock * add multiproofProofThreshold to DeployConfig.s.sol to fix CI failures * Correct semver comment * Regenerate semver-lock following fix --------- Co-authored-by: roger-bai-coinbase * Simplify AggregateVerifier and make it more modular for further proof systems * allow bond refund after 14 days * fix build and tests * forge fmt * forge fmt * pr feedback * semver lock * Clean up AggregateVerifier * Remove challenge after nullification * semver lock * Clean up * semver lock * fix: nullifying zk challenge has to use original intermediate root * forge fmt * fix: use starting anchor root when there is no parent game * merge from main * forge clean and rebuild * fix forge fmt * pr feedback --------- Co-authored-by: Leopold Joy Co-authored-by: Joby Thundil --- interfaces/multiproof/IVerifier.sol | 11 + scripts/deploy/DeployImplementations.s.sol | 4 +- scripts/multiproof/DeployDevNoNitro.s.sol | 8 +- scripts/multiproof/DeployDevWithNitro.s.sol | 8 +- snapshots/abi/DevSystemConfigGlobal.json | 458 ++++++++++++++++++ snapshots/abi/MockSystemConfig.json | 33 ++ snapshots/abi/MockVerifier.json | 31 ++ snapshots/semver-lock.json | 16 +- .../storageLayout/DevSystemConfigGlobal.json | 65 +++ snapshots/storageLayout/MockSystemConfig.json | 9 + snapshots/storageLayout/MockVerifier.json | 1 + src/multiproof/AggregateVerifier.sol | 307 ++++++------ src/multiproof/Verifier.sol | 42 ++ src/multiproof/mocks/MockVerifier.sol | 9 +- src/multiproof/tee/TEEVerifier.sol | 24 +- test/multiproof/AggregateVerifier.t.sol | 26 +- test/multiproof/BaseTest.t.sol | 4 +- test/multiproof/Challenge.t.sol | 139 +++--- test/multiproof/Nullify.t.sol | 34 +- test/multiproof/TEEVerifier.t.sol | 8 +- 20 files changed, 959 insertions(+), 278 deletions(-) create mode 100644 snapshots/abi/DevSystemConfigGlobal.json create mode 100644 snapshots/abi/MockSystemConfig.json create mode 100644 snapshots/abi/MockVerifier.json create mode 100644 snapshots/storageLayout/DevSystemConfigGlobal.json create mode 100644 snapshots/storageLayout/MockSystemConfig.json create mode 100644 snapshots/storageLayout/MockVerifier.json create mode 100644 src/multiproof/Verifier.sol diff --git a/interfaces/multiproof/IVerifier.sol b/interfaces/multiproof/IVerifier.sol index d6a6b8745..e1ae29a54 100644 --- a/interfaces/multiproof/IVerifier.sol +++ b/interfaces/multiproof/IVerifier.sol @@ -2,5 +2,16 @@ pragma solidity 0.8.15; interface IVerifier { + + /// @notice Verifies a proof. + /// @param proofBytes The proof. + /// @param imageId The image ID. + /// @param journal The journal. + /// @return valid Whether the proof is valid. function verify(bytes calldata proofBytes, bytes32 imageId, bytes32 journal) external view returns (bool); + + /// @notice Nullifies the prover to prevent further proof verification. + /// @dev Should only occur if a soundness issue is found. + /// @dev Should only be callable by a proper dispute game. + function nullify() external; } diff --git a/scripts/deploy/DeployImplementations.s.sol b/scripts/deploy/DeployImplementations.s.sol index a4676f0d2..6ba8570a2 100644 --- a/scripts/deploy/DeployImplementations.s.sol +++ b/scripts/deploy/DeployImplementations.s.sol @@ -717,14 +717,14 @@ contract DeployImplementations is Script { } function deployAggregateVerifierImpl(Input memory _input, Output memory _output) private { - address zkVerifier = address(new MockVerifier()); + address zkVerifier = address(new MockVerifier(_output.anchorStateRegistryImpl)); address teeVerifierImpl; { SystemConfigGlobal scgImpl = new SystemConfigGlobal(INitroEnclaveVerifier(_input.nitroEnclaveVerifier)); vm.label(address(scgImpl), "SystemConfigGlobalImpl"); _output.systemConfigGlobalImpl = scgImpl; - teeVerifierImpl = address(new TEEVerifier(scgImpl)); + teeVerifierImpl = address(new TEEVerifier(scgImpl, _output.anchorStateRegistryImpl)); } _output.aggregateVerifierImpl = IVerifier( diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index 2cb9cd95e..de32d62a7 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -120,9 +120,9 @@ contract DeployDevNoNitro is Script { vm.startBroadcast(); - _deployTEEContracts(cfg.finalSystemOwner()); _registerProposer(cfg.teeProposer()); _deployInfrastructure(gameType); + _deployTEEContracts(cfg.finalSystemOwner()); _deployAggregateVerifier(gameType); vm.stopBroadcast(); @@ -140,7 +140,9 @@ contract DeployDevNoNitro is Script { ); console.log("DevSystemConfigGlobal:", systemConfigGlobalProxy); - teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); + teeVerifier = address( + new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy), IAnchorStateRegistry(mockAnchorRegistry)) + ); console.log("TEEVerifier:", teeVerifier); } @@ -173,7 +175,7 @@ contract DeployDevNoNitro is Script { } function _deployAggregateVerifier(GameType gameType) internal { - address zkVerifier = address(new MockVerifier()); + address zkVerifier = address(new MockVerifier(IAnchorStateRegistry(mockAnchorRegistry))); console.log("MockVerifier (ZK):", zkVerifier); mockDelayedWETH = address(new MockDelayedWETH()); diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index c4c808d3a..be9edf89b 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -154,9 +154,9 @@ contract DeployDevWithNitro is Script { vm.startBroadcast(); - _deployTEEContracts(cfg.finalSystemOwner(), cfg.nitroEnclaveVerifier()); _registerProposer(cfg.teeProposer()); _deployInfrastructure(gameType); + _deployTEEContracts(cfg.finalSystemOwner(), cfg.nitroEnclaveVerifier()); _deployAggregateVerifier(gameType); vm.stopBroadcast(); @@ -175,7 +175,9 @@ contract DeployDevWithNitro is Script { ); console.log("SystemConfigGlobal:", systemConfigGlobalProxy); - teeVerifier = address(new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy))); + teeVerifier = address( + new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy), IAnchorStateRegistry(mockAnchorRegistry)) + ); console.log("TEEVerifier:", teeVerifier); } @@ -208,7 +210,7 @@ contract DeployDevWithNitro is Script { } function _deployAggregateVerifier(GameType gameType) internal { - address zkVerifier = address(new MockVerifier()); + address zkVerifier = address(new MockVerifier(IAnchorStateRegistry(mockAnchorRegistry))); console.log("MockVerifier (ZK):", zkVerifier); mockDelayedWETH = address(new MockDelayedWETH()); 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/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/semver-lock.json b/snapshots/semver-lock.json index 16200188b..f241f702d 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -240,12 +240,12 @@ "sourceCodeHash": "0x955bd0c9b47e43219865e4e92abf28d916c96de20cbdf2f94c8ab14d02083759" }, "src/multiproof/AggregateVerifier.sol:AggregateVerifier": { - "initCodeHash": "0x6e30a9816642f1ea2887f16223868fcd04ac80c3a42a4583dfc611d8331f8674", - "sourceCodeHash": "0xb9786dc79b4b494d81905235f7bda044c5b1a98ad82416829f5f6948be1175cc" + "initCodeHash": "0xc3866b1d4515c9d7b0ac6679b182d836f79371402d9e649e301b24cf8ae8fade", + "sourceCodeHash": "0x3a079ea52a26c8c38fb0cb3e9a9ff6ec9648cf83786b65c0fc1161e949b8f7e0" }, "src/multiproof/AggregateVerifier.sol:AggregateVerifier:dispute": { - "initCodeHash": "0xc59c62a455533735aa9337d2db88b255713bd4dde20d3345265ec2fafe62af70", - "sourceCodeHash": "0xb9786dc79b4b494d81905235f7bda044c5b1a98ad82416829f5f6948be1175cc" + "initCodeHash": "0xe28eaeecda21594f6db23bb70127daa2b7b71debe38ce65b598f28d78d2561eb", + "sourceCodeHash": "0x3a079ea52a26c8c38fb0cb3e9a9ff6ec9648cf83786b65c0fc1161e949b8f7e0" }, "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal": { "initCodeHash": "0xee219c003a6af440b447e214e43d520e802001ae3d557262a7921ca3d57ebddf", @@ -256,12 +256,12 @@ "sourceCodeHash": "0xe350108585e0855f10bac20d0e8894b3de9afe3be413908b4c59a1036e7a9842" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { - "initCodeHash": "0x78317d9088a26523d938ce0d88ed0134abc60292c0cdb3f8a6a9530638fd9e9a", - "sourceCodeHash": "0x08e6d340b025c5a6c5997ef6fb69e6c14444f9e473b2c5337d6c10b6c89c0b4f" + "initCodeHash": "0x090330a5c64206b523fd5d9e199269268131035c62ff9eb518247a9024c4b703", + "sourceCodeHash": "0x87b0ad3f68294d64b584e54cc719cc3be0624cbab2940a0a341c502dcc69b4fc" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier:dispute": { - "initCodeHash": "0x78317d9088a26523d938ce0d88ed0134abc60292c0cdb3f8a6a9530638fd9e9a", - "sourceCodeHash": "0x08e6d340b025c5a6c5997ef6fb69e6c14444f9e473b2c5337d6c10b6c89c0b4f" + "initCodeHash": "0x090330a5c64206b523fd5d9e199269268131035c62ff9eb518247a9024c4b703", + "sourceCodeHash": "0x87b0ad3f68294d64b584e54cc719cc3be0624cbab2940a0a341c502dcc69b4fc" }, "src/revenue-share/FeeDisburser.sol:FeeDisburser": { "initCodeHash": "0x1278027e3756e2989e80c0a7b513e221a5fe0d3dbd9ded108375a29b2c1f3d57", 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/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/src/multiproof/AggregateVerifier.sol b/src/multiproof/AggregateVerifier.sol index 21d255d48..72499a1c8 100644 --- a/src/multiproof/AggregateVerifier.sol +++ b/src/multiproof/AggregateVerifier.sol @@ -56,10 +56,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @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 // //////////////////////////////////////////////////////////////// @@ -141,18 +137,20 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @notice The amount of the bond. uint256 public bondAmount; - /// @notice The address of the game that countered this game. - address public counteredByGameAddress; + /// @notice The index of the intermediate root that countered this game. + /// @dev The index is 1-based, so the countered intermediate root index is counteredByIntermediateRootIndexPlusOne - + /// 1. 0 is used to indicate that the game was not countered. + uint256 public counteredByIntermediateRootIndexPlusOne; /// @notice The address that provided a proof of the given type. + /// @dev The address is the zero address if no proof has been provided or the proof has been nullified. mapping(ProofType => address) internal proofTypeToProver; /// @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; + uint8 public proofCount; //////////////////////////////////////////////////////////////// // Events // @@ -164,8 +162,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @notice Emitted when a proposal with a TEE proof is challenged with a ZK proof. /// @param challenger The address of the challenger. - /// @param game The game used to challenge this proposal. - event Challenged(address indexed challenger, IDisputeGame game); + /// @param intermediateRootIndex The index of the intermediate root that was countered. + event Challenged(address indexed challenger, uint256 intermediateRootIndex); /// @notice Emitted when the game is proved. /// @param prover The address of the prover. @@ -219,18 +217,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { /// @notice When an invalid proof type is provided. error InvalidProofType(); - /// @notice When no proof was provided. - error NoProofProvided(); - - /// @notice When the countered by game is invalid. - error InvalidCounteredByGame(); - - /// @notice When the countered by game is not resolved. - error CounteredByGameNotResolved(); - - /// @notice When the bond recipient is empty. - error BondRecipientEmpty(); - /// @notice When the intermediate root index is invalid. error InvalidIntermediateRootIndex(); @@ -363,8 +349,8 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { l2SequenceNumber: parentGame.l2SequenceNumber(), root: Hash.wrap(parentGame.rootClaim().raw()) }); } else { - // When there is no parent game, the starting output root is the anchor state for the game type. - (startingOutputRoot.root, startingOutputRoot.l2SequenceNumber) = ANCHOR_STATE_REGISTRY.getAnchorRoot(); + // When there is no parent game, the starting output root is the starting root in the AnchorStateRegistry. + startingOutputRoot = ANCHOR_STATE_REGISTRY.getStartingAnchorRoot(); } // The block number must be BLOCK_INTERVAL blocks after the starting block number. @@ -405,9 +391,10 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { intermediateOutputRoots() ); - _updateProvingData(proofType, gameCreator()); + _proofVerifiedUpdate(proofType, gameCreator()); - emit Proved(gameCreator(), proofType); + // Set the bond recipient to the creator. It can change if challenged successfully. + bondRecipient = gameCreator(); // Deposit the bond. bondAmount = msg.value; @@ -438,9 +425,7 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { l2SequenceNumber(), intermediateOutputRoots() ); - _updateProvingData(proofType, msg.sender); - - emit Proved(msg.sender, proofType); + _proofVerifiedUpdate(proofType, msg.sender); } /// @notice Resolves the game after a proof has been provided and enough time has passed. @@ -452,21 +437,25 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { // The parent game must have resolved. if (parentGameStatus == GameStatus.IN_PROGRESS) revert ParentGameNotResolved(); + bool isChallenged = counteredByIntermediateRootIndexPlusOne > 0; + // If the parent game's claim is invalid, blacklisted, or retired, then the current game's claim is invalid. if (parentGameStatus == GameStatus.CHALLENGER_WINS) { status = GameStatus.CHALLENGER_WINS; } else { // Game must be completed with a valid proof. if (!gameOver()) revert GameNotOver(); - status = GameStatus.DEFENDER_WINS; + // If the game is challenged, status is CHALLENGER_WINS. + // If the game is not challenged, status is DEFENDER_WINS. + status = isChallenged ? GameStatus.CHALLENGER_WINS : 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(); + if (proofCount < PROOF_THRESHOLD) revert NotEnoughProofs(); - // Bond is refunded as no challenge was made or parent is invalid. - bondRecipient = gameCreator(); + // Default bond recipient is the creator. We only change if successfully challenged. + if (isChallenged) { + bondRecipient = proofTypeToProver[ProofType.ZK]; + } // Mark the game as resolved. resolvedAt = Timestamp.wrap(uint64(block.timestamp)); emit Resolved(status); @@ -475,10 +464,16 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { } /// @notice Challenges the TEE proof with a ZK proof. - /// @param gameIndex The index of the game used to challenge. - /// @dev The game used to challenge must have a ZK proof for the same - /// block number but a different root claim as the current game. - function challenge(uint256 gameIndex) external { + /// @param proofBytes The proof bytes. + /// @param intermediateRootIndex The index of the intermediate root to challenge. + /// @param intermediateRootToProve The intermediate root that the proof claims to be correct. + function challenge( + bytes calldata proofBytes, + uint256 intermediateRootIndex, + bytes32 intermediateRootToProve + ) + external + { // Can only challenge a game that has not been challenged or resolved yet. if (status != GameStatus.IN_PROGRESS) revert ClaimAlreadyResolved(); @@ -489,41 +484,48 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { if (_getParentGameStatus() == GameStatus.CHALLENGER_WINS) revert InvalidParentGame(); // The TEE prover must not be empty. - // You should nullify the game if a ZK proof has already been provided. if (proofTypeToProver[ProofType.TEE] == address(0)) revert MissingProof(ProofType.TEE); + // You should nullify the game if a ZK proof has already been provided. + // This also prevents another challenge while the current challenge is in progress. 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. - if (!_isValidChallengingGame(game)) revert InvalidGame(); + // Can only challenge with a ZK proof. + ProofType proofType = ProofType(uint8(proofBytes[0])); + if (proofType != ProofType.ZK) revert InvalidProofType(); - AggregateVerifier challengingGame = AggregateVerifier(address(game)); + _checkIntermediateRoot(intermediateRootIndex, intermediateRootToProve); - // The ZK prover must not be empty. - if (challengingGame.zkProver() == address(0)) revert MissingProof(ProofType.ZK); + (bytes32 startingRoot, uint256 startingL2SequenceNumber, uint256 endingL2SequenceNumber) = + _getStartingIntermediateRootAndL2SequenceNumbers(intermediateRootIndex); - // Update the counteredBy address. - counteredByGameAddress = address(challengingGame); + _verifyProof( + proofBytes[1:], + proofType, + msg.sender, + l1Head().raw(), + startingRoot, + startingL2SequenceNumber, + intermediateRootToProve, + endingL2SequenceNumber, + abi.encodePacked(intermediateRootToProve) + ); - // Set the game as challenged. - status = GameStatus.CHALLENGER_WINS; + // This allows a ZK nullification to be performed. + proofTypeToProver[proofType] = msg.sender; - // Prevent resolution if any proof was somehow able to be provided later. - proofCount = NEGATIVE_PROOF_COUNT; + // This is only in case the ZK proof is nullified, which would lower the proof count. + // If the ZK is nullified, we allow the remaining TEE proof to resolve. + // The expected resolution time can no longer be increased as both proof types have been submitted. + proofCount += 1; - // Update the expected resolution. - _updateExpectedResolution(); + // We purposely increase the resolution to allow for a ZK nullification. + expectedResolution = Timestamp.wrap(uint64(block.timestamp + SLOW_FINALIZATION_DELAY)); - // Set the bond recipient. - // Bond cannot be claimed until the game used to challenge resolves as DEFENDER_WINS. - bondRecipient = challengingGame.zkProver(); + // Store which intermediate root was countered. + counteredByIntermediateRootIndexPlusOne = intermediateRootIndex + 1; // Emit the challenged event. - emit Challenged(challengingGame.zkProver(), game); + emit Challenged(msg.sender, intermediateRootIndex); } /// @notice Nullifies the game if a soundness issue is found. @@ -538,23 +540,27 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { ) external { - if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); - - if (intermediateRootIndex >= intermediateOutputRootsCount()) revert InvalidIntermediateRootIndex(); - - bytes32 proposedIntermediateRoot = intermediateOutputRoot(intermediateRootIndex); - if (proposedIntermediateRoot == intermediateRootToProve) revert IntermediateRootSameAsProposed(); + // Can only nullify if the game is still in progress. + if (status != GameStatus.IN_PROGRESS) revert ClaimAlreadyResolved(); ProofType proofType = ProofType(uint8(proofBytes[0])); - if (proofTypeToProver[proofType] == address(0)) revert MissingProof(proofType); - bytes32 startingRoot = intermediateRootIndex == 0 - ? startingOutputRoot.root.raw() - : intermediateOutputRoot(intermediateRootIndex - 1); - uint256 startingL2SequenceNumber = - startingOutputRoot.l2SequenceNumber + intermediateRootIndex * INTERMEDIATE_BLOCK_INTERVAL; - uint256 endingL2SequenceNumber = startingL2SequenceNumber + INTERMEDIATE_BLOCK_INTERVAL; + // If this game has been challenged, can only nullify the challenged intermediate root and only with ZK. + if (counteredByIntermediateRootIndexPlusOne > 0) { + if (intermediateRootIndex != counteredByIntermediateRootIndexPlusOne - 1) { + revert InvalidIntermediateRootIndex(); + } + if (intermediateRootToProve != intermediateOutputRoot(intermediateRootIndex)) { + revert IntermediateRootMismatch(intermediateRootToProve, intermediateOutputRoot(intermediateRootIndex)); + } + if (proofType != ProofType.ZK) revert InvalidProofType(); + } else { + _checkIntermediateRoot(intermediateRootIndex, intermediateRootToProve); + } + + (bytes32 startingRoot, uint256 startingL2SequenceNumber, uint256 endingL2SequenceNumber) = + _getStartingIntermediateRootAndL2SequenceNumbers(intermediateRootIndex); _verifyProof( proofBytes[1:], @@ -568,33 +574,19 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { abi.encodePacked(intermediateRootToProve) ); + _proofRefutedUpdate(proofType); + + emit Nullified(msg.sender, intermediateRootIndex, intermediateRootToProve); + + // Nullify the verifier to prevent further proof verification. 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; + // Delete the challenged intermediate root if one existed. + delete counteredByIntermediateRootIndexPlusOne; - // Set the game as challenged so that child games can't resolve. - status = GameStatus.CHALLENGER_WINS; + IVerifier(ZK_VERIFIER).nullify(); } 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)); + IVerifier(TEE_VERIFIER).nullify(); } - - // 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); } /// @notice Claim the credit belonging to the bond recipient. Reverts if the game isn't @@ -603,19 +595,13 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { // The bond must not have been claimed yet. if (bondClaimed) revert NoCreditToClaim(); - // The bond recipient must not be empty. - if (bondRecipient == address(0)) revert BondRecipientEmpty(); - - // If this game was challenged, the countered by game must be valid or else the bond is refunded. - if (counteredByGameAddress != address(0)) { - GameStatus counteredByGameStatus = IDisputeGame(counteredByGameAddress).status(); - if (counteredByGameStatus == GameStatus.IN_PROGRESS) { - revert CounteredByGameNotResolved(); - } - // If the countered by game is invalid or not resolved, the bond is refunded. - if (!_isValidChallengingGame(IDisputeGame(counteredByGameAddress))) { - bondRecipient = gameCreator(); - } + // The game must have resolved or 14 days have passed since creation. + // 14 days chosen as the proof system should have progressed enough so this can't update the + // anchor state registry anymore. + if (expectedResolution.raw() != type(uint64).max) { + if (resolvedAt.raw() == 0) revert GameNotResolved(); + } else { + if (block.timestamp < createdAt.raw() + 14 days) revert GameNotOver(); } if (!bondUnlocked) { @@ -625,10 +611,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { } bondClaimed = true; - // This can fail if this game was challenged and the countered by game is - // blacklisted/retired after it resolved to DEFENDER_WINS. - // The centralized functions in DELAYED_WETH will handle this as it's a already - // a very centralized action to blacklist/retire a valid challenging game. DELAYED_WETH.withdraw(bondRecipient, bondAmount); // Transfer the credit to the bond recipient. @@ -766,13 +748,22 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { return _getArgUint32(0x74); } - /// @notice Updates the expected resolution timestamp. - function _updateExpectedResolution() internal { + function _proofVerifiedUpdate(ProofType proofType, address prover) internal { + proofTypeToProver[proofType] = prover; + proofCount += 1; + + _decreaseExpectedResolution(); + + emit Proved(prover, proofType); + } + + /// @notice Decreases the expected resolution timestamp. + function _decreaseExpectedResolution() internal { uint64 delay; if (proofCount >= 2) { delay = FAST_FINALIZATION_DELAY; - } else if (proofCount >= 1) { + } else if (proofCount == 1) { delay = SLOW_FINALIZATION_DELAY; } else { // If there are no proofs, don't allow the game to resolve. @@ -780,21 +771,41 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { return; } + // Only allow decreases to the expected resolution. uint64 newResolution = uint64(block.timestamp) + delay; expectedResolution = Timestamp.wrap(uint64(FixedPointMathLib.min(newResolution, expectedResolution.raw()))); } - function _updateProvingData(ProofType proofType, address prover) internal { - proofTypeToProver[proofType] = prover; + /// @dev Should only occur if challenged or nullified. + function _proofRefutedUpdate(ProofType proofType) internal { + delete proofTypeToProver[proofType]; - // Bond can be reclaimed after a ZK proof is provided. - if (proofType == ProofType.ZK) { - bondRecipient = gameCreator(); + // Should not be possible, but just in case. + if (proofCount == 0) revert NotEnoughProofs(); + unchecked { + proofCount -= 1; } - proofCount += 1; + _increaseExpectedResolution(); + } + + function _increaseExpectedResolution() internal { + uint64 delay; + + 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; + } - _updateExpectedResolution(); + // We purposely increase the resolution even if it's longer than it should be + // as this can only occur if there is an issue with the proof system so + // we give enough time to resolve the issue and possibly blacklist this game. + expectedResolution = Timestamp.wrap(uint64(block.timestamp) + delay); } function _verifyProof( @@ -930,22 +941,6 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { && !ANCHOR_STATE_REGISTRY.isGameRetired(game) && (game.status() != GameStatus.CHALLENGER_WINS); } - /// @notice Checks if the game is a valid game used to challenge or nullify. - /// @param game The game to check. - function _isValidChallengingGame(IDisputeGame game) internal view returns (bool) { - return - // The game type must be the same. - game.gameType().raw() == GAME_TYPE.raw() && - // The parent game must be the same. - AggregateVerifier(address(game)).parentIndex() == parentIndex() && - // The block number must be the same. - game.l2SequenceNumber() == l2SequenceNumber() && - // The root claim must be different. - game.rootClaim().raw() != rootClaim().raw() && - // The game must be valid. - _isValidGame(game); - } - /// @notice Verifies that the claimed L1 origin hash matches the actual blockhash. /// @param l1OriginHash The L1 block hash claimed in the proof. /// @param l1OriginNumber The L1 block number claimed in the proof. @@ -983,6 +978,36 @@ contract AggregateVerifier is Clone, ReentrancyGuard, ISemver { } } + /// @notice Checks if the intermediate root index is valid and that the intermediate root differs from the proposed + /// intermediate root. + ///@param intermediateRootIndex The index of the intermediate root to check. + /// @param intermediateRootToProve The intermediate root that the proof claims to be correct. + function _checkIntermediateRoot(uint256 intermediateRootIndex, bytes32 intermediateRootToProve) internal view { + if (intermediateRootIndex >= intermediateOutputRootsCount()) revert InvalidIntermediateRootIndex(); + if (intermediateOutputRoot(intermediateRootIndex) == intermediateRootToProve) { + revert IntermediateRootSameAsProposed(); + } + } + + /// @notice Gets the starting intermediate root and the starting and ending L2 sequence numbers. + /// @param intermediateRootIndex The index of the intermediate root to get the starting intermediate root and L2 + /// sequence numbers for. @return startingRoot The starting intermediate root. + /// @return startingL2SequenceNumber The starting L2 sequence number. + /// @return endingL2SequenceNumber The ending L2 sequence number. + function _getStartingIntermediateRootAndL2SequenceNumbers(uint256 intermediateRootIndex) + internal + view + returns (bytes32, uint256, uint256) + { + bytes32 startingRoot = intermediateRootIndex == 0 + ? startingOutputRoot.root.raw() + : intermediateOutputRoot(intermediateRootIndex - 1); + uint256 startingL2SequenceNumber = + startingOutputRoot.l2SequenceNumber + intermediateRootIndex * INTERMEDIATE_BLOCK_INTERVAL; + uint256 endingL2SequenceNumber = startingL2SequenceNumber + INTERMEDIATE_BLOCK_INTERVAL; + return (startingRoot, startingL2SequenceNumber, endingL2SequenceNumber); + } + /// @notice Semantic version. /// @custom:semver 0.1.0 function version() public pure virtual returns (string memory) { diff --git a/src/multiproof/Verifier.sol b/src/multiproof/Verifier.sol new file mode 100644 index 000000000..a792f11dd --- /dev/null +++ b/src/multiproof/Verifier.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; + +abstract contract Verifier is IVerifier { + /// @notice The anchor state registry. + IAnchorStateRegistry public immutable ANCHOR_STATE_REGISTRY; + + /// @notice Whether this verifier has been nullified. + /// @dev This is used to prevent further proof verification after a soundness issue is found. + bool public nullified; + + /// @notice Thrown when the verifier has been nullified. + error Nullified(); + + /// @notice Thrown when the caller trying to nullify is not a proper dispute game. + error NotProperGame(); + + /// @notice Modifier to prevent execution if the verifier has been nullified. + modifier notNullified() { + if (nullified) revert Nullified(); + _; + } + + constructor(IAnchorStateRegistry anchorStateRegistry) { + ANCHOR_STATE_REGISTRY = anchorStateRegistry; + } + + /// @notice Nullifies the verifier to prevent further proof verification. + /// @dev Should only occur if a soundness issue is found. + /// @dev Should only be callable by a proper dispute game. + function nullify() external override { + if ( + !ANCHOR_STATE_REGISTRY.isGameProper(IDisputeGame(msg.sender)) + || !ANCHOR_STATE_REGISTRY.isGameRespected(IDisputeGame(msg.sender)) + ) revert NotProperGame(); + nullified = true; + } +} diff --git a/src/multiproof/mocks/MockVerifier.sol b/src/multiproof/mocks/MockVerifier.sol index fff83d15d..c9093337b 100644 --- a/src/multiproof/mocks/MockVerifier.sol +++ b/src/multiproof/mocks/MockVerifier.sol @@ -1,10 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; +import { Verifier } from "../Verifier.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -contract MockVerifier is IVerifier { - function verify(bytes calldata, bytes32, bytes32) external pure returns (bool) { +contract MockVerifier is Verifier { + constructor(IAnchorStateRegistry anchorStateRegistry) Verifier(anchorStateRegistry) { } + + function verify(bytes calldata, bytes32, bytes32) external view override notNullified returns (bool) { return true; } } diff --git a/src/multiproof/tee/TEEVerifier.sol b/src/multiproof/tee/TEEVerifier.sol index 5bbf4e90c..ea35faa4c 100644 --- a/src/multiproof/tee/TEEVerifier.sol +++ b/src/multiproof/tee/TEEVerifier.sol @@ -3,10 +3,11 @@ 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 { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { SystemConfigGlobal } from "./SystemConfigGlobal.sol"; +import { Verifier } from "../Verifier.sol"; /// @title TEEVerifier /// @notice Stateless TEE proof verifier that validates signatures against registered signers. @@ -15,7 +16,7 @@ import { SystemConfigGlobal } from "./SystemConfigGlobal.sol"; /// via AWS Nitro attestation, and that the signer's PCR0 matches the claimed imageId. /// 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 { +contract TEEVerifier is Verifier, 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; @@ -37,7 +38,12 @@ contract TEEVerifier is IVerifier, ISemver { /// @notice Constructs the TEEVerifier contract. /// @param systemConfigGlobal The SystemConfigGlobal contract address. - constructor(SystemConfigGlobal systemConfigGlobal) { + constructor( + SystemConfigGlobal systemConfigGlobal, + IAnchorStateRegistry anchorStateRegistry + ) + Verifier(anchorStateRegistry) + { SYSTEM_CONFIG_GLOBAL = systemConfigGlobal; } @@ -46,7 +52,17 @@ contract TEEVerifier is IVerifier, ISemver { /// @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) { + function verify( + bytes calldata proofBytes, + bytes32 imageId, + bytes32 journal + ) + external + view + override + notNullified + returns (bool) + { if (proofBytes.length < 85) revert InvalidProofFormat(); address proposer = address(bytes20(proofBytes[0:20])); diff --git a/test/multiproof/AggregateVerifier.t.sol b/test/multiproof/AggregateVerifier.t.sol index d7d00dff1..a60f081ee 100644 --- a/test/multiproof/AggregateVerifier.t.sol +++ b/test/multiproof/AggregateVerifier.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.15; -import { BadExtraData } from "src/dispute/lib/Errors.sol"; +import { BadExtraData, GameNotResolved } from "src/dispute/lib/Errors.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; @@ -34,7 +34,7 @@ contract AggregateVerifierTest is BaseTest { assertEq( game.extraData(), abi.encodePacked(currentL2BlockNumber, type(uint32).max, game.intermediateOutputRoots()) ); - assertEq(game.bondRecipient(), address(0)); + assertEq(game.bondRecipient(), TEE_PROVER); assertEq(anchorStateRegistry.isGameProper(IDisputeGame(address(game))), true); assertEq(delayedWETH.balanceOf(address(game)), INIT_BOND); assertEq(game.proofCount(), 1); @@ -87,8 +87,8 @@ contract AggregateVerifierTest is BaseTest { AggregateVerifier game = _createAggregateVerifierGame(TEE_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); - // Cannot claim bond before resolving - vm.expectRevert(AggregateVerifier.BondRecipientEmpty.selector); + // Cannot claim bond before game is over + vm.expectRevert(GameNotResolved.selector); game.claimCredit(); // Resolve after 7 days @@ -120,6 +120,11 @@ contract AggregateVerifierTest is BaseTest { AggregateVerifier game = _createAggregateVerifierGame(ZK_PROVER, rootClaim, currentL2BlockNumber, type(uint32).max, proof); + // Resolve after 7 days + vm.warp(block.timestamp + 7 days); + game.resolve(); + assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); + // Unlock and reclaim bond after delay uint256 balanceBefore = game.gameCreator().balance; game.claimCredit(); @@ -128,11 +133,6 @@ contract AggregateVerifierTest is BaseTest { assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); assertEq(delayedWETH.balanceOf(address(game)), 0); - // Resolve after another 7 days - vm.warp(block.timestamp + 7 days); - game.resolve(); - assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); - // Update AnchorStateRegistry vm.warp(block.timestamp + 1); game.closeGame(); @@ -153,11 +153,7 @@ contract AggregateVerifierTest is BaseTest { _provideProof(game, ZK_PROVER, zkProof); assertEq(game.proofCount(), 2); - // Unlock bond - uint256 balanceBefore = game.gameCreator().balance; - game.claimCredit(); - - // Resolve after 1 day + // Resolve after 1 day (FAST_FINALIZATION_DELAY with 2 proofs) vm.warp(block.timestamp + 1 days); game.resolve(); assertEq(uint8(game.status()), uint8(GameStatus.DEFENDER_WINS)); @@ -170,6 +166,8 @@ contract AggregateVerifierTest is BaseTest { assertEq(l2SequenceNumber, currentL2BlockNumber); // Unlock and reclaim bond after delay + uint256 balanceBefore = game.gameCreator().balance; + game.claimCredit(); vm.warp(block.timestamp + DELAYED_WETH_DELAY); game.claimCredit(); assertEq(game.gameCreator().balance, balanceBefore + INIT_BOND); diff --git a/test/multiproof/BaseTest.t.sol b/test/multiproof/BaseTest.t.sol index 69cd7dd72..c47811464 100644 --- a/test/multiproof/BaseTest.t.sol +++ b/test/multiproof/BaseTest.t.sol @@ -101,8 +101,8 @@ contract BaseTest is Test { delayedWETH = DelayedWETH(payable(address(delayedWETHProxy))); // Deploy the verifiers - teeVerifier = new MockVerifier(); - zkVerifier = new MockVerifier(); + teeVerifier = new MockVerifier(IAnchorStateRegistry(address(anchorStateRegistry))); + zkVerifier = new MockVerifier(IAnchorStateRegistry(address(anchorStateRegistry))); } function _initializeProxies() internal { diff --git a/test/multiproof/Challenge.t.sol b/test/multiproof/Challenge.t.sol index 3d0ef2f65..aefe5a4de 100644 --- a/test/multiproof/Challenge.t.sol +++ b/test/multiproof/Challenge.t.sol @@ -7,6 +7,7 @@ import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { Claim, GameStatus, Hash } from "src/dispute/lib/Types.sol"; import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; +import { Verifier } from "src/multiproof/Verifier.sol"; import { BaseTest } from "./BaseTest.t.sol"; @@ -14,44 +15,37 @@ contract ChallengeTest is BaseTest { function testChallengeTEEProofWithZKProof() public { currentL2BlockNumber += BLOCK_INTERVAL; - // Create first game with TEE proof + // Create game with TEE proof Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); - AggregateVerifier game1 = + AggregateVerifier game = _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); - // Create second game with different root claim and ZK proof + // Challenge game with ZK proof Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); - AggregateVerifier game2 = - _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); + vm.prank(ZK_PROVER); + game.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); - // Get game index from factory - uint256 gameIndex = factory.gameCount() - 1; + assertEq(uint8(game.status()), uint8(GameStatus.IN_PROGRESS)); + // 2 proofs so that it can decrease to 1 if ZK is nullified and then the TEE proof can resolve + assertEq(game.proofCount(), 2); - // Challenge game1 with game2 - game1.challenge(gameIndex); + // Resolve after SLOW_FINALIZATION_DELAY + vm.warp(block.timestamp + 7 days); + game.resolve(); - assertEq(uint8(game1.status()), uint8(GameStatus.CHALLENGER_WINS)); - assertEq(game1.bondRecipient(), ZK_PROVER); - address counteredBy = game1.counteredByGameAddress(); - assertEq(counteredBy, address(game2)); - assertEq(game1.proofCount(), -128); - assertEq(game1.expectedResolution().raw(), type(uint64).max); + assertEq(uint8(game.status()), uint8(GameStatus.CHALLENGER_WINS)); + assertEq(game.bondRecipient(), ZK_PROVER); - // Retrieve bond after challenge - vm.warp(block.timestamp + 7 days); - game2.resolve(); - assertEq(uint8(game2.status()), uint8(GameStatus.DEFENDER_WINS)); - assertEq(ZK_PROVER.balance, 0); - assertEq(delayedWETH.balanceOf(address(game1)), INIT_BOND); - game1.claimCredit(); + uint256 balanceBefore = ZK_PROVER.balance; + game.claimCredit(); vm.warp(block.timestamp + DELAYED_WETH_DELAY); - game1.claimCredit(); - assertEq(ZK_PROVER.balance, INIT_BOND); - assertEq(delayedWETH.balanceOf(address(game1)), 0); + game.claimCredit(); + assertEq(ZK_PROVER.balance, balanceBefore + INIT_BOND); + assertEq(delayedWETH.balanceOf(address(game)), 0); } function testChallengeFailsIfNoTEEProof() public { @@ -64,45 +58,16 @@ contract ChallengeTest is BaseTest { AggregateVerifier game1 = _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, zkProof1); - // Create second game with different root claim and ZK proof - Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk2"))); + // Challenge game with ZK proof bytes memory zkProof2 = _generateProof("zk-proof-2", AggregateVerifier.ProofType.ZK); - _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof2); - - uint256 gameIndex = factory.gameCount() - 1; - vm.expectRevert( abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.TEE) ); - game1.challenge(gameIndex); - } - - function testChallengeFailsIfDifferentParentIndex() public { - currentL2BlockNumber += BLOCK_INTERVAL; - - Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); - bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); - - AggregateVerifier game1 = - _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); - - // Create game2 with game1 as parent - uint256 game1Index = factory.gameCount() - 1; - uint256 nextBlockNumber = currentL2BlockNumber + BLOCK_INTERVAL; - Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(nextBlockNumber, "zk"))); - bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); - - // forge-lint: disable-next-line(unsafe-typecast) - _createAggregateVerifierGame(ZK_PROVER, rootClaim2, nextBlockNumber, uint32(game1Index), zkProof); - - uint256 gameIndex = factory.gameCount() - 1; - - vm.expectRevert(AggregateVerifier.InvalidGame.selector); - game1.challenge(gameIndex); + game1.challenge(zkProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim1.raw()); } - function testChallengeFailsIfChallengingGameHasNoZKProof() public { + function testChallengeFailsIfNotZKProof() public { currentL2BlockNumber += BLOCK_INTERVAL; Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee1"))); @@ -114,12 +79,8 @@ contract ChallengeTest is BaseTest { Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee2"))); bytes memory teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); - _createAggregateVerifierGame(TEE_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, teeProof2); - - uint256 gameIndex = factory.gameCount() - 1; - - vm.expectRevert(abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.ZK)); - game1.challenge(gameIndex); + vm.expectRevert(AggregateVerifier.InvalidProofType.selector); + game1.challenge(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); } function testChallengeFailsIfGameAlreadyResolved() public { @@ -139,11 +100,8 @@ contract ChallengeTest is BaseTest { Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); - _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); - - uint256 challengeIndex1 = factory.gameCount() - 1; vm.expectRevert(ClaimAlreadyResolved.selector); - game1.challenge(challengeIndex1); + game1.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); } function testChallengeFailsIfParentGameStatusIsChallenged() public { @@ -160,7 +118,7 @@ contract ChallengeTest is BaseTest { currentL2BlockNumber += BLOCK_INTERVAL; // create child game - Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee2"))); bytes memory childProof = _generateProof("child-proof", AggregateVerifier.ProofType.TEE); AggregateVerifier childGame = @@ -170,10 +128,12 @@ contract ChallengeTest is BaseTest { // blacklist parent game anchorStateRegistry.blacklistDisputeGame(IDisputeGame(address(parentGame))); - // challenge child game - uint256 childGameIndex = factory.gameCount() - 1; + // challenge child game with ZK proof + Claim rootClaim3 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + vm.expectRevert(AggregateVerifier.InvalidParentGame.selector); - childGame.challenge(childGameIndex); + childGame.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim3.raw()); } function testChallengeFailsIfGameItselfIsBlacklisted() public { @@ -188,9 +148,11 @@ contract ChallengeTest is BaseTest { anchorStateRegistry.blacklistDisputeGame(IDisputeGame(address(game))); // challenge game - uint256 gameIndex = factory.gameCount() - 1; + Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + vm.expectRevert(AggregateVerifier.InvalidGame.selector); - game.challenge(gameIndex); + game.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); } function testChallengeFailsAfterTEENullification() public { @@ -207,28 +169,37 @@ contract ChallengeTest is BaseTest { 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); + // challenge game — TEE proof was nullified, so MissingProof(TEE) is expected + Claim rootClaim3 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); + bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); + + vm.expectRevert( + abi.encodeWithSelector(AggregateVerifier.MissingProof.selector, AggregateVerifier.ProofType.TEE) + ); + game.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim3.raw()); } function testChallengeFailsAfterZKNullification() public { currentL2BlockNumber += BLOCK_INTERVAL; - Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk1"))); + Claim rootClaim1 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "tee"))); + bytes memory teeProof = _generateProof("tee-proof", AggregateVerifier.ProofType.TEE); bytes memory zkProof1 = _generateProof("zk-proof-1", AggregateVerifier.ProofType.ZK); + // create game with both proofs AggregateVerifier game = - _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, zkProof1); + _createAggregateVerifierGame(ZK_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof); + game.verifyProposalProof(zkProof1); + // nullify ZK proof 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); + // challenge game — ZK is nullified so Nullified() is expected + Claim rootClaim3 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk3"))); + bytes memory zkProof3 = _generateProof("zk-proof-3", AggregateVerifier.ProofType.ZK); + + vm.expectRevert(Verifier.Nullified.selector); + game.challenge(zkProof3, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim3.raw()); } } diff --git a/test/multiproof/Nullify.t.sol b/test/multiproof/Nullify.t.sol index 9ee51c066..4674fc381 100644 --- a/test/multiproof/Nullify.t.sol +++ b/test/multiproof/Nullify.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.15; -import { GameNotInProgress } from "src/dispute/lib/Errors.sol"; +import { ClaimAlreadyResolved } from "src/dispute/lib/Errors.sol"; import { Claim, GameStatus } from "src/dispute/lib/Types.sol"; import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; @@ -28,6 +28,9 @@ contract NullifyTest is BaseTest { assertEq(game.proofCount(), 0); assertEq(game.expectedResolution().raw(), type(uint64).max); + // expectedResolution is uint64.max (no proofs left), so must wait 14 days from creation + vm.warp(block.timestamp + 14 days); + uint256 balanceBefore = game.gameCreator().balance; game.claimCredit(); vm.warp(block.timestamp + DELAYED_WETH_DELAY); @@ -50,11 +53,14 @@ contract NullifyTest is BaseTest { game1.nullify(zkProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); - assertEq(uint8(game1.status()), uint8(GameStatus.CHALLENGER_WINS)); + assertEq(uint8(game1.status()), uint8(GameStatus.IN_PROGRESS)); assertEq(game1.bondRecipient(), ZK_PROVER); - assertEq(game1.proofCount(), -128); + assertEq(game1.proofCount(), 0); assertEq(game1.expectedResolution().raw(), type(uint64).max); + // expectedResolution is uint64.max (no proofs left), so must wait 14 days from creation + vm.warp(block.timestamp + 14 days); + uint256 balanceBefore = game1.gameCreator().balance; game1.claimCredit(); vm.warp(block.timestamp + DELAYED_WETH_DELAY); @@ -120,7 +126,7 @@ contract NullifyTest is BaseTest { Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); bytes memory teeProof2 = _generateProof("tee-proof-2", AggregateVerifier.ProofType.TEE); - vm.expectRevert(GameNotInProgress.selector); + vm.expectRevert(ClaimAlreadyResolved.selector); game1.nullify(teeProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); } @@ -133,23 +139,25 @@ contract NullifyTest is BaseTest { AggregateVerifier game1 = _createAggregateVerifierGame(TEE_PROVER, rootClaim1, currentL2BlockNumber, type(uint32).max, teeProof1); - // Challenge game1 + // Challenge game1 with ZK proof Claim rootClaim2 = Claim.wrap(keccak256(abi.encode(currentL2BlockNumber, "zk"))); bytes memory zkProof = _generateProof("zk-proof", AggregateVerifier.ProofType.ZK); - AggregateVerifier game2 = - _createAggregateVerifierGame(ZK_PROVER, rootClaim2, currentL2BlockNumber, type(uint32).max, zkProof); - - uint256 challengeIndex = factory.gameCount() - 1; - game1.challenge(challengeIndex); - assertEq(game1.bondRecipient(), ZK_PROVER); + vm.prank(ZK_PROVER); + game1.challenge(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim2.raw()); // Nullify can override challenge - game2.nullify(zkProof, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim1.raw()); + bytes memory zkProof2 = _generateProof("zk-proof-2", AggregateVerifier.ProofType.ZK); + game1.nullify(zkProof2, BLOCK_INTERVAL / INTERMEDIATE_BLOCK_INTERVAL - 1, rootClaim1.raw()); + + assertEq(game1.bondRecipient(), TEE_PROVER); + + // After nullify, only TEE proof remains; expectedResolution = now + 7 days + vm.warp(block.timestamp + 7 days); + game1.resolve(); uint256 balanceBefore = game1.gameCreator().balance; game1.claimCredit(); - assertEq(game1.bondRecipient(), TEE_PROVER); vm.warp(block.timestamp + DELAYED_WETH_DELAY); game1.claimCredit(); assertEq(game1.gameCreator().balance, balanceBefore + INIT_BOND); diff --git a/test/multiproof/TEEVerifier.t.sol b/test/multiproof/TEEVerifier.t.sol index 3a1095d95..3b19a0c55 100644 --- a/test/multiproof/TEEVerifier.t.sol +++ b/test/multiproof/TEEVerifier.t.sol @@ -9,7 +9,9 @@ import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; import { INitroEnclaveVerifier } from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; +import { MockAnchorStateRegistry } from "scripts/multiproof/mocks/MockAnchorStateRegistry.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"; @@ -18,6 +20,7 @@ contract TEEVerifierTest is Test { TEEVerifier public verifier; DevSystemConfigGlobal public systemConfigGlobal; ProxyAdmin public proxyAdmin; + MockAnchorStateRegistry public anchorStateRegistry; // Test signer - we'll derive address from private key uint256 internal constant SIGNER_PRIVATE_KEY = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; @@ -55,7 +58,10 @@ contract TEEVerifierTest is Test { systemConfigGlobal.setProposer(PROPOSER, true); // Deploy TEEVerifier - verifier = new TEEVerifier(SystemConfigGlobal(address(systemConfigGlobal))); + anchorStateRegistry = new MockAnchorStateRegistry(); + verifier = new TEEVerifier( + SystemConfigGlobal(address(systemConfigGlobal)), IAnchorStateRegistry(address(anchorStateRegistry)) + ); } function testVerifyValidSignature() public view { From 88ac6bd0f65301cfb1f9f6dde4aa5dc718f1ddf8 Mon Sep 17 00:00:00 2001 From: Leopold Joy Date: Thu, 12 Mar 2026 15:08:36 +0000 Subject: [PATCH 05/18] Rename SystemConfigGlobal to TEEProverRegistry (#205) * refactor: rename SystemConfigGlobal to TEEProverRegistry * fix: align ASCII tables in deploy script comments Co-Authored-By: Claude Opus 4.6 (1M context) * fix: regenerate semver-lock and snapshots after clean build Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- deployments/11155111-dev-no-nitro.json | 2 +- scripts/deploy/Deploy.s.sol | 2 +- scripts/deploy/DeployImplementations.s.sol | 10 +- scripts/multiproof/DeployDevNoNitro.s.sol | 50 ++-- scripts/multiproof/DeployDevWithNitro.s.sol | 56 ++--- snapshots/abi/AggregateVerifier.json | 77 ++++-- ...gGlobal.json => DevTEEProverRegistry.json} | 13 + snapshots/abi/MockVerifier.json | 56 ++++- ...nfigGlobal.json => TEEProverRegistry.json} | 13 + snapshots/abi/TEEVerifier.json | 56 ++++- snapshots/semver-lock.json | 16 +- .../storageLayout/AggregateVerifier.json | 13 +- ...gGlobal.json => DevTEEProverRegistry.json} | 7 + snapshots/storageLayout/MockVerifier.json | 10 +- ...nfigGlobal.json => TEEProverRegistry.json} | 7 + snapshots/storageLayout/TEEVerifier.json | 10 +- ...lobal.sol => MockDevTEEProverRegistry.sol} | 10 +- ...ConfigGlobal.sol => TEEProverRegistry.sol} | 4 +- src/multiproof/tee/TEEVerifier.sol | 20 +- ...igGlobal.t.sol => TEEProverRegistry.t.sol} | 230 +++++++++--------- test/multiproof/TEEVerifier.t.sol | 20 +- test/setup/Setup.sol | 6 +- test/vendor/Initializable.t.sol | 10 +- 23 files changed, 447 insertions(+), 251 deletions(-) rename snapshots/abi/{DevSystemConfigGlobal.json => DevTEEProverRegistry.json} (97%) rename snapshots/abi/{SystemConfigGlobal.json => TEEProverRegistry.json} (97%) rename snapshots/storageLayout/{DevSystemConfigGlobal.json => DevTEEProverRegistry.json} (87%) rename snapshots/storageLayout/{SystemConfigGlobal.json => TEEProverRegistry.json} (87%) rename src/multiproof/mocks/{MockDevSystemConfigGlobal.sol => MockDevTEEProverRegistry.sol} (73%) rename src/multiproof/tee/{SystemConfigGlobal.sol => TEEProverRegistry.sol} (98%) rename test/multiproof/{SystemConfigGlobal.t.sol => TEEProverRegistry.t.sol} (60%) diff --git a/deployments/11155111-dev-no-nitro.json b/deployments/11155111-dev-no-nitro.json index f98679b2f..5d7f92521 100644 --- a/deployments/11155111-dev-no-nitro.json +++ b/deployments/11155111-dev-no-nitro.json @@ -1 +1 @@ -{"SystemConfigGlobal":"0xf8293c0f3a36A746B559a1a51870339B20F60945","TEEVerifier":"0x82453dA61B397EE366fB2129502de9c216480aB6","DisputeGameFactory":"0xfEa8Cb315F75d838b6c76ae336a9255f81df0D50","AnchorStateRegistry":"0x556BD554854504BE2F2023F6531D25eF6f6Fe77D","DelayedWETH":"0xb1FB7f05711d2270cD658448562A29E8c5C95E9E","AggregateVerifier":"0xeeF18F1640fa79f919799B5D629908909e715f97"} \ No newline at end of file +{"TEEProverRegistry":"0x8897f8E1379C7548caE146e0ee26f6b1108A8570","TEEVerifier":"0xB319EA8fAac05BB01ABcce3671BC66c5A1f9A077","DisputeGameFactory":"0xF2e2f5F97e1aE0899924bE4Dd1D1795052Ea7551","AnchorStateRegistry":"0x59C17E560057A1cF2327E6Be35b070E46e4EC8b4","DelayedWETH":"0xD455276eF429eE495d91567BF3e78066bdfAc2b8","AggregateVerifier":"0x3EE78cfac34D7Cbe49D35B901B354272d2084951"} \ No newline at end of file diff --git a/scripts/deploy/Deploy.s.sol b/scripts/deploy/Deploy.s.sol index 77d2ddd47..cc91cad7a 100644 --- a/scripts/deploy/Deploy.s.sol +++ b/scripts/deploy/Deploy.s.sol @@ -309,7 +309,7 @@ contract Deploy is Deployer { artifacts.save("PreimageOracle", address(dio.preimageOracleSingleton)); artifacts.save("PermissionedDisputeGame", address(dio.permissionedDisputeGameV2Impl)); artifacts.save("AggregateVerifier", address(dio.aggregateVerifierImpl)); - artifacts.save("SystemConfigGlobal", address(dio.systemConfigGlobalImpl)); + artifacts.save("TEEProverRegistry", address(dio.teeProverRegistryImpl)); // Get a contract set from the implementation addresses which were just deployed. Types.ContractSet memory impls = ChainAssertions.dioToContractSet(dio); diff --git a/scripts/deploy/DeployImplementations.s.sol b/scripts/deploy/DeployImplementations.s.sol index 6ba8570a2..f38f2807a 100644 --- a/scripts/deploy/DeployImplementations.s.sol +++ b/scripts/deploy/DeployImplementations.s.sol @@ -47,7 +47,7 @@ import { DevFeatures } from "src/libraries/DevFeatures.sol"; import { INitroEnclaveVerifier } from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; import { AggregateVerifier } from "src/multiproof/AggregateVerifier.sol"; @@ -114,7 +114,7 @@ contract DeployImplementations is Script { ISuperFaultDisputeGame superFaultDisputeGameImpl; ISuperPermissionedDisputeGame superPermissionedDisputeGameImpl; IVerifier aggregateVerifierImpl; - SystemConfigGlobal systemConfigGlobalImpl; + TEEProverRegistry teeProverRegistryImpl; } bytes32 internal _salt = DeployUtils.DEFAULT_SALT; @@ -721,9 +721,9 @@ contract DeployImplementations is Script { address teeVerifierImpl; { - SystemConfigGlobal scgImpl = new SystemConfigGlobal(INitroEnclaveVerifier(_input.nitroEnclaveVerifier)); - vm.label(address(scgImpl), "SystemConfigGlobalImpl"); - _output.systemConfigGlobalImpl = scgImpl; + TEEProverRegistry scgImpl = new TEEProverRegistry(INitroEnclaveVerifier(_input.nitroEnclaveVerifier)); + vm.label(address(scgImpl), "TEEProverRegistryImpl"); + _output.teeProverRegistryImpl = scgImpl; teeVerifierImpl = address(new TEEVerifier(scgImpl, _output.anchorStateRegistryImpl)); } diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index de32d62a7..7206759c7 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -9,7 +9,7 @@ pragma solidity 0.8.15; * DEPLOYMENT TYPE: DEV (NO NITRO) * ══════════════════════════════════════════════════════════════════════════════════ * - * This script deploys infrastructure using DevSystemConfigGlobal, which BYPASSES + * This script deploys infrastructure using DevTEEProverRegistry, which BYPASSES * AWS Nitro attestation validation. Signers can be registered with a simple call * to addDevSigner() without needing a real Nitro enclave or attestation document. * @@ -28,7 +28,7 @@ pragma solidity 0.8.15; * * After deployment, register a signer with a single call: * - * cast send $SYSTEM_CONFIG_GLOBAL \ + * cast send $TEE_PROVER_REGISTRY \ * "addDevSigner(address,bytes32)" $SIGNER_ADDRESS $TEE_IMAGE_HASH \ * --private-key $OWNER_KEY --rpc-url $RPC_URL * @@ -38,14 +38,14 @@ pragma solidity 0.8.15; * COMPARISON WITH DeployDevWithNitro * ───────────────────────────────────────────────────────────────────────────────── * - * | Feature | DeployDevNoNitro | DeployDevWithNitro | - * |----------------------------|----------------------|------------------------| - * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | - * | Signer registration | addDevSigner() | registerSigner() | - * | Requires Nitro enclave | No | Yes | - * | Validates attestation (ZK) | No | Yes | - * | PCR0 pre-registration | No | Yes | - * | Attestation freshness | N/A | < 60 minutes | + * | Feature | DeployDevNoNitro | DeployDevWithNitro | + * |----------------------------|------------------------|------------------------| + * | TEEProverRegistry | DevTEEProverRegistry | TEEProverRegistry | + * | Signer registration | addDevSigner() | registerSigner() | + * | Requires Nitro enclave | No | Yes | + * | Validates attestation (ZK) | No | Yes | + * | PCR0 pre-registration | No | Yes | + * | Attestation freshness | N/A | < 60 minutes | * * Both scripts use mocks for AnchorStateRegistry, DelayedWETH, and ZK Verifier. * @@ -71,8 +71,8 @@ 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"; -import { DevSystemConfigGlobal } from "src/multiproof/mocks/MockDevSystemConfigGlobal.sol"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { DevTEEProverRegistry } from "src/multiproof/mocks/MockDevTEEProverRegistry.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; import { MinimalProxyAdmin } from "./mocks/MinimalProxyAdmin.sol"; @@ -81,7 +81,7 @@ import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; /// @title DeployDevNoNitro /// @notice Development deployment WITHOUT AWS Nitro attestation validation. -/// @dev Uses DevSystemConfigGlobal which allows addDevSigner() to bypass attestation. +/// @dev Uses DevTEEProverRegistry which allows addDevSigner() to bypass attestation. contract DeployDevNoNitro is Script { /// @notice Constant from Optimism's Constants.sol - the storage slot for proxy admin. bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; @@ -95,7 +95,7 @@ contract DeployDevNoNitro is Script { DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); // Deployed addresses - address public systemConfigGlobalProxy; + address public teeProverRegistryProxy; address public teeVerifier; address public disputeGameFactory; address public mockAnchorRegistry; @@ -116,7 +116,7 @@ contract DeployDevNoNitro is Script { console.log("TEE Proposer:", cfg.teeProposer()); console.log("Game Type:", cfg.multiproofGameType()); console.log(""); - console.log("NOTE: Using DevSystemConfigGlobal - NO attestation required."); + console.log("NOTE: Using DevTEEProverRegistry - NO attestation required."); vm.startBroadcast(); @@ -132,22 +132,22 @@ contract DeployDevNoNitro is Script { } function _deployTEEContracts(address owner) internal { - address scgImpl = address(new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0)))); - systemConfigGlobalProxy = address( + address scgImpl = address(new DevTEEProverRegistry(INitroEnclaveVerifier(address(0)))); + teeProverRegistryProxy = address( new TransparentUpgradeableProxy( - scgImpl, address(0xdead), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + scgImpl, address(0xdead), abi.encodeCall(TEEProverRegistry.initialize, (owner, owner)) ) ); - console.log("DevSystemConfigGlobal:", systemConfigGlobalProxy); + console.log("DevTEEProverRegistry:", teeProverRegistryProxy); teeVerifier = address( - new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy), IAnchorStateRegistry(mockAnchorRegistry)) + new TEEVerifier(TEEProverRegistry(teeProverRegistryProxy), IAnchorStateRegistry(mockAnchorRegistry)) ); console.log("TEEVerifier:", teeVerifier); } function _registerProposer(address teeProposer) internal { - SystemConfigGlobal(systemConfigGlobalProxy).setProposer(teeProposer, true); + TEEProverRegistry(teeProverRegistryProxy).setProposer(teeProposer, true); console.log("Registered TEE proposer:", teeProposer); } @@ -209,7 +209,7 @@ contract DeployDevNoNitro is Script { console.log(" DEV DEPLOYMENT COMPLETE (NO NITRO)"); console.log("========================================"); console.log("\nTEE Contracts:"); - console.log(" DevSystemConfigGlobal:", systemConfigGlobalProxy); + console.log(" DevTEEProverRegistry:", teeProverRegistryProxy); console.log(" TEEVerifier:", teeVerifier); console.log("\nInfrastructure:"); console.log(" DisputeGameFactory:", disputeGameFactory); @@ -222,7 +222,7 @@ contract DeployDevNoNitro is Script { 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("\ncast send", teeProverRegistryProxy); console.log(' "addDevSigner(address,bytes32)" '); console.log(" ", vm.toString(cfg.teeImageHash())); console.log(" --private-key --rpc-url "); @@ -232,8 +232,8 @@ 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( - '{"SystemConfigGlobal":"', - vm.toString(systemConfigGlobalProxy), + '{"TEEProverRegistry":"', + vm.toString(teeProverRegistryProxy), '","TEEVerifier":"', vm.toString(teeVerifier), '","DisputeGameFactory":"', diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index be9edf89b..add43ec6f 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -9,7 +9,7 @@ pragma solidity 0.8.15; * DEPLOYMENT TYPE: DEV (WITH NITRO) * ══════════════════════════════════════════════════════════════════════════════════ * - * This script deploys infrastructure using the REAL SystemConfigGlobal, which + * This script deploys infrastructure using the REAL TEEProverRegistry, which * 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. @@ -38,7 +38,7 @@ pragma solidity 0.8.15; * PCR0_RAW="0x<48_bytes_hex>" * * # Register it (only owner can do this) - * cast send $SYSTEM_CONFIG_GLOBAL "registerPCR0(bytes)" $PCR0_RAW \ + * cast send $TEE_PROVER_REGISTRY "registerPCR0(bytes)" $PCR0_RAW \ * --private-key $OWNER_KEY --rpc-url $RPC_URL * * Note: The teeImageHash in deploy-config is keccak256(PCR0_RAW), not the raw bytes. @@ -49,7 +49,7 @@ pragma solidity 0.8.15; * * Generate a Risc0 ZK proof of the Nitro attestation offchain, then call: * - * cast send $SYSTEM_CONFIG_GLOBAL \ + * cast send $TEE_PROVER_REGISTRY \ * "registerSigner(bytes,bytes)" $ZK_OUTPUT $ZK_PROOF_BYTES \ * --private-key $OWNER_OR_MANAGER_KEY --rpc-url $RPC_URL * @@ -63,23 +63,23 @@ pragma solidity 0.8.15; * After registration, verify the signer is registered: * * # Check if signer is valid - * cast call $SYSTEM_CONFIG_GLOBAL "isValidSigner(address)(bool)" $SIGNER_ADDRESS + * cast call $TEE_PROVER_REGISTRY "isValidSigner(address)(bool)" $SIGNER_ADDRESS * * # Get the PCR0 hash associated with the signer - * cast call $SYSTEM_CONFIG_GLOBAL "signerPCR0(address)(bytes32)" $SIGNER_ADDRESS + * cast call $TEE_PROVER_REGISTRY "signerPCR0(address)(bytes32)" $SIGNER_ADDRESS * * ───────────────────────────────────────────────────────────────────────────────── * COMPARISON WITH DeployDevNoNitro * ───────────────────────────────────────────────────────────────────────────────── * - * | Feature | DeployDevNoNitro | DeployDevWithNitro | - * |----------------------------|----------------------|------------------------| - * | SystemConfigGlobal | DevSystemConfigGlobal | SystemConfigGlobal | - * | Signer registration | addDevSigner() | registerSigner() | - * | Requires Nitro enclave | No | Yes | - * | Validates attestation (ZK) | No | Yes | - * | PCR0 pre-registration | No | Yes | - * | Attestation freshness | N/A | < 60 minutes | + * | Feature | DeployDevNoNitro | DeployDevWithNitro | + * |----------------------------|------------------------|------------------------| + * | TEEProverRegistry | DevTEEProverRegistry | TEEProverRegistry | + * | Signer registration | addDevSigner() | registerSigner() | + * | Requires Nitro enclave | No | Yes | + * | Validates attestation (ZK) | No | Yes | + * | PCR0 pre-registration | No | Yes | + * | Attestation freshness | N/A | < 60 minutes | * * Both scripts use mocks for AnchorStateRegistry, DelayedWETH, and ZK Verifier. * @@ -105,7 +105,7 @@ 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"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; import { MinimalProxyAdmin } from "./mocks/MinimalProxyAdmin.sol"; @@ -114,7 +114,7 @@ import { MockDelayedWETH } from "./mocks/MockDelayedWETH.sol"; /// @title DeployDevWithNitro /// @notice Development deployment WITH AWS Nitro attestation validation. -/// @dev Uses real SystemConfigGlobal which requires registerSigner() with valid attestation. +/// @dev Uses real TEEProverRegistry which requires registerSigner() with valid attestation. contract DeployDevWithNitro is Script { /// @notice Constant from Optimism's Constants.sol - the storage slot for proxy admin. bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; @@ -128,7 +128,7 @@ contract DeployDevWithNitro is Script { DeployConfig(address(uint160(uint256(keccak256(abi.encode("optimism.deployconfig")))))); // Deployed addresses - address public systemConfigGlobalProxy; + address public teeProverRegistryProxy; address public teeVerifier; address public disputeGameFactory; address public mockAnchorRegistry; @@ -149,7 +149,7 @@ contract DeployDevWithNitro is Script { console.log("TEE Proposer:", cfg.teeProposer()); console.log("Game Type:", cfg.multiproofGameType()); console.log(""); - console.log("NOTE: Using REAL SystemConfigGlobal - ZK attestation proof REQUIRED."); + console.log("NOTE: Using REAL TEEProverRegistry - ZK attestation proof REQUIRED."); console.log("NitroEnclaveVerifier:", cfg.nitroEnclaveVerifier()); vm.startBroadcast(); @@ -166,23 +166,23 @@ contract DeployDevWithNitro is Script { } function _deployTEEContracts(address owner, address _nitroEnclaveVerifier) internal { - address scgImpl = address(new SystemConfigGlobal(INitroEnclaveVerifier(_nitroEnclaveVerifier))); + address scgImpl = address(new TEEProverRegistry(INitroEnclaveVerifier(_nitroEnclaveVerifier))); console.log("NitroEnclaveVerifier (external):", _nitroEnclaveVerifier); - systemConfigGlobalProxy = address( + teeProverRegistryProxy = address( new TransparentUpgradeableProxy( - scgImpl, address(0xdead), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + scgImpl, address(0xdead), abi.encodeCall(TEEProverRegistry.initialize, (owner, owner)) ) ); - console.log("SystemConfigGlobal:", systemConfigGlobalProxy); + console.log("TEEProverRegistry:", teeProverRegistryProxy); teeVerifier = address( - new TEEVerifier(SystemConfigGlobal(systemConfigGlobalProxy), IAnchorStateRegistry(mockAnchorRegistry)) + new TEEVerifier(TEEProverRegistry(teeProverRegistryProxy), IAnchorStateRegistry(mockAnchorRegistry)) ); console.log("TEEVerifier:", teeVerifier); } function _registerProposer(address teeProposer) internal { - SystemConfigGlobal(systemConfigGlobalProxy).setProposer(teeProposer, true); + TEEProverRegistry(teeProverRegistryProxy).setProposer(teeProposer, true); console.log("Registered TEE proposer:", teeProposer); } @@ -245,7 +245,7 @@ contract DeployDevWithNitro is Script { console.log("========================================"); console.log("\nTEE Contracts:"); console.log(" NitroEnclaveVerifier (external):", cfg.nitroEnclaveVerifier()); - console.log(" SystemConfigGlobal:", systemConfigGlobalProxy); + console.log(" TEEProverRegistry:", teeProverRegistryProxy); console.log(" TEEVerifier:", teeVerifier); console.log("\nInfrastructure:"); console.log(" DisputeGameFactory:", disputeGameFactory); @@ -259,12 +259,12 @@ contract DeployDevWithNitro is Script { console.log("========================================"); 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(" cast send", teeProverRegistryProxy); console.log(' "registerPCR0(bytes)" '); console.log(" --private-key --rpc-url "); 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(" cast send", teeProverRegistryProxy); 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."); @@ -274,8 +274,8 @@ 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( - '{"SystemConfigGlobal":"', - vm.toString(systemConfigGlobalProxy), + '{"TEEProverRegistry":"', + vm.toString(teeProverRegistryProxy), '","TEEVerifier":"', vm.toString(teeVerifier), '","DisputeGameFactory":"', diff --git a/snapshots/abi/AggregateVerifier.json b/snapshots/abi/AggregateVerifier.json index 2a142bdd7..38f06763e 100644 --- a/snapshots/abi/AggregateVerifier.json +++ b/snapshots/abi/AggregateVerifier.json @@ -55,6 +55,11 @@ "internalType": "uint256", "name": "intermediateBlockInterval", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "proofThreshold", + "type": "uint256" } ], "stateMutability": "nonpayable", @@ -190,6 +195,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "PROOF_THRESHOLD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "SLOW_FINALIZATION_DELAY", @@ -322,10 +340,20 @@ }, { "inputs": [ + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + }, { "internalType": "uint256", - "name": "gameIndex", + "name": "intermediateRootIndex", "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "intermediateRootToProve", + "type": "bytes32" } ], "name": "challenge", @@ -349,12 +377,12 @@ }, { "inputs": [], - "name": "counteredByGameAddress", + "name": "counteredByIntermediateRootIndexPlusOne", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], "stateMutability": "view", @@ -581,6 +609,19 @@ "stateMutability": "pure", "type": "function" }, + { + "inputs": [], + "name": "proofCount", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "resolve", @@ -753,9 +794,9 @@ }, { "indexed": false, - "internalType": "contract IDisputeGame", - "name": "game", - "type": "address" + "internalType": "uint256", + "name": "intermediateRootIndex", + "type": "uint256" } ], "name": "Challenged", @@ -853,11 +894,6 @@ "name": "AlreadyProven", "type": "error" }, - { - "inputs": [], - "name": "BondRecipientEmpty", - "type": "error" - }, { "inputs": [], "name": "BondTransferFailed", @@ -868,11 +904,6 @@ "name": "ClaimAlreadyResolved", "type": "error" }, - { - "inputs": [], - "name": "CounteredByGameNotResolved", - "type": "error" - }, { "inputs": [], "name": "GameNotFinalized", @@ -940,11 +971,6 @@ "name": "InvalidBlockInterval", "type": "error" }, - { - "inputs": [], - "name": "InvalidCounteredByGame", - "type": "error" - }, { "inputs": [], "name": "InvalidGame", @@ -965,6 +991,11 @@ "name": "InvalidProof", "type": "error" }, + { + "inputs": [], + "name": "InvalidProofThreshold", + "type": "error" + }, { "inputs": [], "name": "InvalidProofType", @@ -1036,7 +1067,7 @@ }, { "inputs": [], - "name": "NoProofProvided", + "name": "NotEnoughProofs", "type": "error" }, { diff --git a/snapshots/abi/DevSystemConfigGlobal.json b/snapshots/abi/DevTEEProverRegistry.json similarity index 97% rename from snapshots/abi/DevSystemConfigGlobal.json rename to snapshots/abi/DevTEEProverRegistry.json index a082b6f79..6a61389fd 100644 --- a/snapshots/abi/DevSystemConfigGlobal.json +++ b/snapshots/abi/DevTEEProverRegistry.json @@ -80,6 +80,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "getRegisteredSigners", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/snapshots/abi/MockVerifier.json b/snapshots/abi/MockVerifier.json index d36cb2b27..7129f5617 100644 --- a/snapshots/abi/MockVerifier.json +++ b/snapshots/abi/MockVerifier.json @@ -1,4 +1,48 @@ [ + { + "inputs": [ + { + "internalType": "contract IAnchorStateRegistry", + "name": "anchorStateRegistry", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ANCHOR_STATE_REGISTRY", + "outputs": [ + { + "internalType": "contract IAnchorStateRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nullified", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nullify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -25,7 +69,17 @@ "type": "bool" } ], - "stateMutability": "pure", + "stateMutability": "view", "type": "function" + }, + { + "inputs": [], + "name": "NotProperGame", + "type": "error" + }, + { + "inputs": [], + "name": "Nullified", + "type": "error" } ] \ No newline at end of file diff --git a/snapshots/abi/SystemConfigGlobal.json b/snapshots/abi/TEEProverRegistry.json similarity index 97% rename from snapshots/abi/SystemConfigGlobal.json rename to snapshots/abi/TEEProverRegistry.json index e2e1a3db9..7250c1f7d 100644 --- a/snapshots/abi/SystemConfigGlobal.json +++ b/snapshots/abi/TEEProverRegistry.json @@ -62,6 +62,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "getRegisteredSigners", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/snapshots/abi/TEEVerifier.json b/snapshots/abi/TEEVerifier.json index b1bccadb7..4e408dd33 100644 --- a/snapshots/abi/TEEVerifier.json +++ b/snapshots/abi/TEEVerifier.json @@ -2,8 +2,13 @@ { "inputs": [ { - "internalType": "contract SystemConfigGlobal", - "name": "systemConfigGlobal", + "internalType": "contract TEEProverRegistry", + "name": "teeProverRegistry", + "type": "address" + }, + { + "internalType": "contract IAnchorStateRegistry", + "name": "anchorStateRegistry", "type": "address" } ], @@ -12,10 +17,23 @@ }, { "inputs": [], - "name": "SYSTEM_CONFIG_GLOBAL", + "name": "ANCHOR_STATE_REGISTRY", + "outputs": [ + { + "internalType": "contract IAnchorStateRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TEE_PROVER_REGISTRY", "outputs": [ { - "internalType": "contract SystemConfigGlobal", + "internalType": "contract TEEProverRegistry", "name": "", "type": "address" } @@ -23,6 +41,26 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "nullified", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nullify", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -112,5 +150,15 @@ ], "name": "InvalidSigner", "type": "error" + }, + { + "inputs": [], + "name": "NotProperGame", + "type": "error" + }, + { + "inputs": [], + "name": "Nullified", + "type": "error" } ] \ No newline at end of file diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index f241f702d..7316eb4b5 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -247,21 +247,21 @@ "initCodeHash": "0xe28eaeecda21594f6db23bb70127daa2b7b71debe38ce65b598f28d78d2561eb", "sourceCodeHash": "0x3a079ea52a26c8c38fb0cb3e9a9ff6ec9648cf83786b65c0fc1161e949b8f7e0" }, - "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal": { + "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry": { "initCodeHash": "0xee219c003a6af440b447e214e43d520e802001ae3d557262a7921ca3d57ebddf", - "sourceCodeHash": "0xe350108585e0855f10bac20d0e8894b3de9afe3be413908b4c59a1036e7a9842" + "sourceCodeHash": "0x8be9aea4bb16c89a10444da8ce324e3914a2419654a80542692757fbdc9a2f5c" }, - "src/multiproof/tee/SystemConfigGlobal.sol:SystemConfigGlobal:dispute": { + "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry:dispute": { "initCodeHash": "0x8ae045f0121d2c63ab6f0a830be842aaf0445096bfabe29d85cfd9bd38b40565", - "sourceCodeHash": "0xe350108585e0855f10bac20d0e8894b3de9afe3be413908b4c59a1036e7a9842" + "sourceCodeHash": "0x8be9aea4bb16c89a10444da8ce324e3914a2419654a80542692757fbdc9a2f5c" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { - "initCodeHash": "0x090330a5c64206b523fd5d9e199269268131035c62ff9eb518247a9024c4b703", - "sourceCodeHash": "0x87b0ad3f68294d64b584e54cc719cc3be0624cbab2940a0a341c502dcc69b4fc" + "initCodeHash": "0xd65f1d604f979045a86d662e168cb7a867478da8a0ca294181872a90d209a66f", + "sourceCodeHash": "0xe8aa3c0710ee72546da52957730c11dc932065c444a013658bd2f5fd0c79085d" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier:dispute": { - "initCodeHash": "0x090330a5c64206b523fd5d9e199269268131035c62ff9eb518247a9024c4b703", - "sourceCodeHash": "0x87b0ad3f68294d64b584e54cc719cc3be0624cbab2940a0a341c502dcc69b4fc" + "initCodeHash": "0xd65f1d604f979045a86d662e168cb7a867478da8a0ca294181872a90d209a66f", + "sourceCodeHash": "0xe8aa3c0710ee72546da52957730c11dc932065c444a013658bd2f5fd0c79085d" }, "src/revenue-share/FeeDisburser.sol:FeeDisburser": { "initCodeHash": "0x1278027e3756e2989e80c0a7b513e221a5fe0d3dbd9ded108375a29b2c1f3d57", diff --git a/snapshots/storageLayout/AggregateVerifier.json b/snapshots/storageLayout/AggregateVerifier.json index 1045c4170..08fd716cb 100644 --- a/snapshots/storageLayout/AggregateVerifier.json +++ b/snapshots/storageLayout/AggregateVerifier.json @@ -70,11 +70,11 @@ "type": "uint256" }, { - "bytes": "20", - "label": "counteredByGameAddress", + "bytes": "32", + "label": "counteredByIntermediateRootIndexPlusOne", "offset": 0, "slot": "5", - "type": "address" + "type": "uint256" }, { "bytes": "32", @@ -89,5 +89,12 @@ "offset": 0, "slot": "7", "type": "Timestamp" + }, + { + "bytes": "1", + "label": "proofCount", + "offset": 8, + "slot": "7", + "type": "uint8" } ] \ No newline at end of file diff --git a/snapshots/storageLayout/DevSystemConfigGlobal.json b/snapshots/storageLayout/DevTEEProverRegistry.json similarity index 87% rename from snapshots/storageLayout/DevSystemConfigGlobal.json rename to snapshots/storageLayout/DevTEEProverRegistry.json index 2bd347c54..590893632 100644 --- a/snapshots/storageLayout/DevSystemConfigGlobal.json +++ b/snapshots/storageLayout/DevTEEProverRegistry.json @@ -61,5 +61,12 @@ "offset": 0, "slot": "103", "type": "mapping(address => bool)" + }, + { + "bytes": "32", + "label": "_registeredSigners", + "offset": 0, + "slot": "104", + "type": "struct EnumerableSetLib.AddressSet" } ] \ No newline at end of file diff --git a/snapshots/storageLayout/MockVerifier.json b/snapshots/storageLayout/MockVerifier.json index 0637a088a..7b7ad77a9 100644 --- a/snapshots/storageLayout/MockVerifier.json +++ b/snapshots/storageLayout/MockVerifier.json @@ -1 +1,9 @@ -[] \ No newline at end of file +[ + { + "bytes": "1", + "label": "nullified", + "offset": 0, + "slot": "0", + "type": "bool" + } +] \ No newline at end of file diff --git a/snapshots/storageLayout/SystemConfigGlobal.json b/snapshots/storageLayout/TEEProverRegistry.json similarity index 87% rename from snapshots/storageLayout/SystemConfigGlobal.json rename to snapshots/storageLayout/TEEProverRegistry.json index 2bd347c54..590893632 100644 --- a/snapshots/storageLayout/SystemConfigGlobal.json +++ b/snapshots/storageLayout/TEEProverRegistry.json @@ -61,5 +61,12 @@ "offset": 0, "slot": "103", "type": "mapping(address => bool)" + }, + { + "bytes": "32", + "label": "_registeredSigners", + "offset": 0, + "slot": "104", + "type": "struct EnumerableSetLib.AddressSet" } ] \ No newline at end of file diff --git a/snapshots/storageLayout/TEEVerifier.json b/snapshots/storageLayout/TEEVerifier.json index 0637a088a..7b7ad77a9 100644 --- a/snapshots/storageLayout/TEEVerifier.json +++ b/snapshots/storageLayout/TEEVerifier.json @@ -1 +1,9 @@ -[] \ No newline at end of file +[ + { + "bytes": "1", + "label": "nullified", + "offset": 0, + "slot": "0", + "type": "bool" + } +] \ No newline at end of file diff --git a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol b/src/multiproof/mocks/MockDevTEEProverRegistry.sol similarity index 73% rename from src/multiproof/mocks/MockDevSystemConfigGlobal.sol rename to src/multiproof/mocks/MockDevTEEProverRegistry.sol index 4dc6f7159..3d49434c8 100644 --- a/src/multiproof/mocks/MockDevSystemConfigGlobal.sol +++ b/src/multiproof/mocks/MockDevTEEProverRegistry.sol @@ -6,16 +6,16 @@ import { } from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; -/// @title DevSystemConfigGlobal -/// @notice Development version of SystemConfigGlobal with bypassed attestation for testing. +/// @title DevTEEProverRegistry +/// @notice Development version of TEEProverRegistry with bypassed attestation for testing. /// @dev This contract adds addDevSigner() which bypasses AWS Nitro attestation verification. /// DO NOT deploy this contract to production networks. -contract DevSystemConfigGlobal is SystemConfigGlobal { +contract DevTEEProverRegistry is TEEProverRegistry { using EnumerableSetLib for EnumerableSetLib.AddressSet; - constructor(INitroEnclaveVerifier nitroVerifier) SystemConfigGlobal(nitroVerifier) { } + constructor(INitroEnclaveVerifier nitroVerifier) TEEProverRegistry(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/TEEProverRegistry.sol similarity index 98% rename from src/multiproof/tee/SystemConfigGlobal.sol rename to src/multiproof/tee/TEEProverRegistry.sol index c15b876ad..ae3dd38f2 100644 --- a/src/multiproof/tee/SystemConfigGlobal.sol +++ b/src/multiproof/tee/TEEProverRegistry.sol @@ -13,13 +13,13 @@ import { OwnableManagedUpgradeable } from "lib/op-enclave/contracts/src/OwnableM import { ISemver } from "interfaces/universal/ISemver.sol"; import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; -/// @title SystemConfigGlobal +/// @title TEEProverRegistry /// @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, ISemver { +contract TEEProverRegistry is OwnableManagedUpgradeable, ISemver { using EnumerableSetLib for EnumerableSetLib.AddressSet; /// @notice Maximum age of an attestation document (60 minutes), in seconds. uint256 public constant MAX_AGE = 60 minutes; diff --git a/src/multiproof/tee/TEEVerifier.sol b/src/multiproof/tee/TEEVerifier.sol index ea35faa4c..ba61a30c5 100644 --- a/src/multiproof/tee/TEEVerifier.sol +++ b/src/multiproof/tee/TEEVerifier.sol @@ -6,20 +6,20 @@ import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { ISemver } from "interfaces/universal/ISemver.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { SystemConfigGlobal } from "./SystemConfigGlobal.sol"; +import { TEEProverRegistry } from "./TEEProverRegistry.sol"; import { Verifier } from "../Verifier.sol"; /// @title TEEVerifier /// @notice Stateless TEE proof verifier that validates signatures against registered signers. /// @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 +/// It verifies that proofs are signed by enclave addresses registered in TEEProverRegistry /// via AWS Nitro attestation, and that the signer's PCR0 matches the claimed imageId. /// 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 Verifier, 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; + /// @notice The TEEProverRegistry contract that manages valid TEE signers. + /// @dev Signers are registered via AWS Nitro attestation in TEEProverRegistry. + TEEProverRegistry public immutable TEE_PROVER_REGISTRY; /// @notice Thrown when the recovered signer is not a valid registered signer. error InvalidSigner(address signer); @@ -37,14 +37,14 @@ contract TEEVerifier is Verifier, ISemver { error InvalidProposer(address proposer); /// @notice Constructs the TEEVerifier contract. - /// @param systemConfigGlobal The SystemConfigGlobal contract address. + /// @param teeProverRegistry The TEEProverRegistry contract address. constructor( - SystemConfigGlobal systemConfigGlobal, + TEEProverRegistry teeProverRegistry, IAnchorStateRegistry anchorStateRegistry ) Verifier(anchorStateRegistry) { - SYSTEM_CONFIG_GLOBAL = systemConfigGlobal; + TEE_PROVER_REGISTRY = teeProverRegistry; } /// @notice Verifies a TEE proof for a state transition. @@ -76,12 +76,12 @@ contract TEEVerifier is Verifier, ISemver { revert InvalidSignature(); } - if (!SYSTEM_CONFIG_GLOBAL.isValidProposer(proposer)) { + if (!TEE_PROVER_REGISTRY.isValidProposer(proposer)) { revert InvalidProposer(proposer); } // Get the PCR0 the signer was registered with - bytes32 registeredPCR0 = SYSTEM_CONFIG_GLOBAL.signerPCR0(signer); + bytes32 registeredPCR0 = TEE_PROVER_REGISTRY.signerPCR0(signer); // Check that the signer is registered (PCR0 != 0) if (registeredPCR0 == bytes32(0)) { diff --git a/test/multiproof/SystemConfigGlobal.t.sol b/test/multiproof/TEEProverRegistry.t.sol similarity index 60% rename from test/multiproof/SystemConfigGlobal.t.sol rename to test/multiproof/TEEProverRegistry.t.sol index c57409d4b..5b388f5ff 100644 --- a/test/multiproof/SystemConfigGlobal.t.sol +++ b/test/multiproof/TEEProverRegistry.t.sol @@ -10,19 +10,19 @@ 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"; - -/// @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 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 +import { DevTEEProverRegistry } from "src/multiproof/mocks/MockDevTEEProverRegistry.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; + +/// @notice Tests for TEEProverRegistry and DevTEEProverRegistry contracts. +/// @dev IMPORTANT: This test file uses DevTEEProverRegistry as the implementation because +/// registering signers on the production TEEProverRegistry requires a ZK proof of a valid +/// AWS Nitro attestation, which cannot be generated in a test environment. DevTEEProverRegistry extends +/// TEEProverRegistry with an `addDevSigner` function that bypasses attestation verification, +/// allowing us to test all signer-related functionality. All tests for base TEEProverRegistry /// 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; +/// DevTEEProverRegistry inherits from TEEProverRegistry without modifying those functions. +contract TEEProverRegistryTest is Test { + DevTEEProverRegistry public teeProverRegistry; ProxyAdmin public proxyAdmin; address public owner; @@ -47,27 +47,27 @@ contract SystemConfigGlobalTest is Test { pcr0Hash = keccak256(TEST_PCR0); - // Deploy implementation (using DevSystemConfigGlobal for test flexibility) + // Deploy implementation (using DevTEEProverRegistry for test flexibility) // NitroEnclaveVerifier is not needed since tests use addDevSigner(), so pass address(0). - DevSystemConfigGlobal impl = new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0))); + DevTEEProverRegistry impl = new DevTEEProverRegistry(INitroEnclaveVerifier(address(0))); // Deploy proxy admin proxyAdmin = new ProxyAdmin(address(this)); // Deploy proxy TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( - address(impl), address(proxyAdmin), abi.encodeCall(SystemConfigGlobal.initialize, (owner, manager)) + address(impl), address(proxyAdmin), abi.encodeCall(TEEProverRegistry.initialize, (owner, manager)) ); - systemConfigGlobal = DevSystemConfigGlobal(address(proxy)); + teeProverRegistry = DevTEEProverRegistry(address(proxy)); } // ============ Initialization Tests ============ function testInitialization() public view { - assertEq(systemConfigGlobal.owner(), owner); - assertEq(systemConfigGlobal.manager(), manager); - assertEq(systemConfigGlobal.version(), "0.2.0"); + assertEq(teeProverRegistry.owner(), owner); + assertEq(teeProverRegistry.manager(), manager); + assertEq(teeProverRegistry.version(), "0.2.0"); } // ============ PCR0 Registration Tests ============ @@ -77,44 +77,44 @@ contract SystemConfigGlobalTest is Test { emit PCR0Registered(pcr0Hash); vm.prank(owner); - systemConfigGlobal.registerPCR0(TEST_PCR0); + teeProverRegistry.registerPCR0(TEST_PCR0); - assertTrue(systemConfigGlobal.validPCR0s(pcr0Hash)); + assertTrue(teeProverRegistry.validPCR0s(pcr0Hash)); } function testRegisterPCR0FailsIfNotOwner() public { vm.prank(manager); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.registerPCR0(TEST_PCR0); + teeProverRegistry.registerPCR0(TEST_PCR0); vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.registerPCR0(TEST_PCR0); + teeProverRegistry.registerPCR0(TEST_PCR0); } function testDeregisterPCR0() public { // First register vm.prank(owner); - systemConfigGlobal.registerPCR0(TEST_PCR0); - assertTrue(systemConfigGlobal.validPCR0s(pcr0Hash)); + teeProverRegistry.registerPCR0(TEST_PCR0); + assertTrue(teeProverRegistry.validPCR0s(pcr0Hash)); // Then deregister vm.expectEmit(true, false, false, false); emit PCR0Deregistered(pcr0Hash); vm.prank(owner); - systemConfigGlobal.deregisterPCR0(TEST_PCR0); + teeProverRegistry.deregisterPCR0(TEST_PCR0); - assertFalse(systemConfigGlobal.validPCR0s(pcr0Hash)); + assertFalse(teeProverRegistry.validPCR0s(pcr0Hash)); } function testDeregisterPCR0FailsIfNotOwner() public { vm.prank(owner); - systemConfigGlobal.registerPCR0(TEST_PCR0); + teeProverRegistry.registerPCR0(TEST_PCR0); vm.prank(manager); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.deregisterPCR0(TEST_PCR0); + teeProverRegistry.deregisterPCR0(TEST_PCR0); } // ============ Signer Deregistration Tests ============ @@ -123,38 +123,38 @@ contract SystemConfigGlobalTest is Test { address signer = makeAddr("signer"); bytes32 signerPcr0 = keccak256("signer-pcr0"); - // Add signer via DevSystemConfigGlobal + // Add signer via DevTEEProverRegistry vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); // Verify signer is registered - assertTrue(systemConfigGlobal.isValidSigner(signer)); + assertTrue(teeProverRegistry.isValidSigner(signer)); // Deregister as owner vm.expectEmit(true, false, false, false); emit SignerDeregistered(signer); vm.prank(owner); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); - assertFalse(systemConfigGlobal.isValidSigner(signer)); - assertEq(systemConfigGlobal.signerPCR0(signer), bytes32(0)); + assertFalse(teeProverRegistry.isValidSigner(signer)); + assertEq(teeProverRegistry.signerPCR0(signer), bytes32(0)); } function testDeregisterSignerAsManager() public { address signer = makeAddr("signer"); bytes32 signerPcr0 = keccak256("signer-pcr0"); - // Add signer via DevSystemConfigGlobal + // Add signer via DevTEEProverRegistry vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); - assertTrue(systemConfigGlobal.isValidSigner(signer)); + assertTrue(teeProverRegistry.isValidSigner(signer)); vm.prank(manager); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); - assertFalse(systemConfigGlobal.isValidSigner(signer)); + assertFalse(teeProverRegistry.isValidSigner(signer)); } function testDeregisterSignerFailsIfUnauthorized() public { @@ -162,7 +162,7 @@ contract SystemConfigGlobalTest is Test { vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner or the manager"); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); } // ============ Proposer Tests ============ @@ -174,9 +174,9 @@ contract SystemConfigGlobalTest is Test { emit ProposerSet(newProposer, true); vm.prank(owner); - systemConfigGlobal.setProposer(newProposer, true); + teeProverRegistry.setProposer(newProposer, true); - assertTrue(systemConfigGlobal.isValidProposer(newProposer)); + assertTrue(teeProverRegistry.isValidProposer(newProposer)); } function testSetProposerFailsIfNotOwner() public { @@ -184,18 +184,18 @@ contract SystemConfigGlobalTest is Test { vm.prank(manager); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.setProposer(newProposer, true); + teeProverRegistry.setProposer(newProposer, true); vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.setProposer(newProposer, true); + teeProverRegistry.setProposer(newProposer, true); } // ============ isValidSigner Tests ============ function testIsValidSignerReturnsFalseForUnregistered() public { address unregistered = makeAddr("unregistered"); - assertFalse(systemConfigGlobal.isValidSigner(unregistered)); + assertFalse(teeProverRegistry.isValidSigner(unregistered)); } function testIsValidSignerReturnsTrueForRegistered() public { @@ -203,16 +203,16 @@ contract SystemConfigGlobalTest is Test { bytes32 signerPcr0 = keccak256("signer-pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); - assertTrue(systemConfigGlobal.isValidSigner(signer)); + assertTrue(teeProverRegistry.isValidSigner(signer)); } // ============ signerPCR0 Tests ============ function testSignerPCR0ReturnsZeroForUnregistered() public { address unregistered = makeAddr("unregistered"); - assertEq(systemConfigGlobal.signerPCR0(unregistered), bytes32(0)); + assertEq(teeProverRegistry.signerPCR0(unregistered), bytes32(0)); } function testSignerPCR0ReturnsCorrectValue() public { @@ -220,15 +220,15 @@ contract SystemConfigGlobalTest is Test { bytes32 expectedPcr0 = keccak256("signer-pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, expectedPcr0); + teeProverRegistry.addDevSigner(signer, expectedPcr0); - assertEq(systemConfigGlobal.signerPCR0(signer), expectedPcr0); + assertEq(teeProverRegistry.signerPCR0(signer), expectedPcr0); } // ============ MAX_AGE Tests ============ function testMaxAgeConstant() public view { - assertEq(systemConfigGlobal.MAX_AGE(), 60 minutes); + assertEq(teeProverRegistry.MAX_AGE(), 60 minutes); } // ============ Ownership Transfer Tests ============ @@ -237,9 +237,9 @@ contract SystemConfigGlobalTest is Test { address newOwner = makeAddr("newOwner"); vm.prank(owner); - systemConfigGlobal.transferOwnership(newOwner); + teeProverRegistry.transferOwnership(newOwner); - assertEq(systemConfigGlobal.owner(), newOwner); + assertEq(teeProverRegistry.owner(), newOwner); } function testTransferOwnershipFailsIfNotOwner() public { @@ -247,17 +247,17 @@ contract SystemConfigGlobalTest is Test { vm.prank(manager); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.transferOwnership(newOwner); + teeProverRegistry.transferOwnership(newOwner); vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.transferOwnership(newOwner); + teeProverRegistry.transferOwnership(newOwner); } function testTransferOwnershipFailsForZeroAddress() public { vm.prank(owner); vm.expectRevert("OwnableManaged: new owner is the zero address"); - systemConfigGlobal.transferOwnership(address(0)); + teeProverRegistry.transferOwnership(address(0)); } // ============ Management Transfer Tests ============ @@ -266,18 +266,18 @@ contract SystemConfigGlobalTest is Test { address newManager = makeAddr("newManager"); vm.prank(owner); - systemConfigGlobal.transferManagement(newManager); + teeProverRegistry.transferManagement(newManager); - assertEq(systemConfigGlobal.manager(), newManager); + assertEq(teeProverRegistry.manager(), newManager); } function testTransferManagementAsManager() public { address newManager = makeAddr("newManager"); vm.prank(manager); - systemConfigGlobal.transferManagement(newManager); + teeProverRegistry.transferManagement(newManager); - assertEq(systemConfigGlobal.manager(), newManager); + assertEq(teeProverRegistry.manager(), newManager); } function testTransferManagementFailsIfUnauthorized() public { @@ -285,39 +285,39 @@ contract SystemConfigGlobalTest is Test { vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner or the manager"); - systemConfigGlobal.transferManagement(newManager); + teeProverRegistry.transferManagement(newManager); } function testTransferManagementFailsForZeroAddress() public { vm.prank(owner); vm.expectRevert("OwnableManaged: new manager is the zero address"); - systemConfigGlobal.transferManagement(address(0)); + teeProverRegistry.transferManagement(address(0)); } // ============ Renounce Tests ============ function testRenounceOwnership() public { vm.prank(owner); - systemConfigGlobal.renounceOwnership(); + teeProverRegistry.renounceOwnership(); - assertEq(systemConfigGlobal.owner(), address(0)); + assertEq(teeProverRegistry.owner(), address(0)); } function testRenounceManagementAsOwner() public { vm.prank(owner); - systemConfigGlobal.renounceManagement(); + teeProverRegistry.renounceManagement(); - assertEq(systemConfigGlobal.manager(), address(0)); + assertEq(teeProverRegistry.manager(), address(0)); } function testRenounceManagementAsManager() public { vm.prank(manager); - systemConfigGlobal.renounceManagement(); + teeProverRegistry.renounceManagement(); - assertEq(systemConfigGlobal.manager(), address(0)); + assertEq(teeProverRegistry.manager(), address(0)); } - // ============ DevSystemConfigGlobal: addDevSigner Tests ============ + // ============ DevTEEProverRegistry: addDevSigner Tests ============ function testAddDevSigner() public { address signer = makeAddr("dev-signer"); @@ -327,10 +327,10 @@ contract SystemConfigGlobalTest is Test { emit SignerRegistered(signer, devPcr0Hash); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + teeProverRegistry.addDevSigner(signer, devPcr0Hash); - assertTrue(systemConfigGlobal.isValidSigner(signer)); - assertEq(systemConfigGlobal.signerPCR0(signer), devPcr0Hash); + assertTrue(teeProverRegistry.isValidSigner(signer)); + assertEq(teeProverRegistry.signerPCR0(signer), devPcr0Hash); } function testAddDevSignerFailsIfNotOwner() public { @@ -339,11 +339,11 @@ contract SystemConfigGlobalTest is Test { vm.prank(manager); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + teeProverRegistry.addDevSigner(signer, devPcr0Hash); vm.prank(unauthorized); vm.expectRevert("OwnableManaged: caller is not the owner"); - systemConfigGlobal.addDevSigner(signer, devPcr0Hash); + teeProverRegistry.addDevSigner(signer, devPcr0Hash); } function testAddDevSignerCanOverwriteExisting() public { @@ -352,23 +352,23 @@ contract SystemConfigGlobalTest is Test { bytes32 secondPcr0 = keccak256("second-pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, firstPcr0); - assertEq(systemConfigGlobal.signerPCR0(signer), firstPcr0); + teeProverRegistry.addDevSigner(signer, firstPcr0); + assertEq(teeProverRegistry.signerPCR0(signer), firstPcr0); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, secondPcr0); - assertEq(systemConfigGlobal.signerPCR0(signer), secondPcr0); + teeProverRegistry.addDevSigner(signer, secondPcr0); + assertEq(teeProverRegistry.signerPCR0(signer), secondPcr0); } function testAddDevSignerWithZeroPcr0() public { address signer = makeAddr("dev-signer"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, bytes32(0)); + teeProverRegistry.addDevSigner(signer, bytes32(0)); // Signer should not be valid because PCR0 is zero - assertFalse(systemConfigGlobal.isValidSigner(signer)); - assertEq(systemConfigGlobal.signerPCR0(signer), bytes32(0)); + assertFalse(teeProverRegistry.isValidSigner(signer)); + assertEq(teeProverRegistry.signerPCR0(signer), bytes32(0)); } function testAddMultipleDevSigners() public { @@ -381,24 +381,24 @@ contract SystemConfigGlobalTest is Test { bytes32 pcr0Hash3 = keccak256("pcr0-3"); vm.startPrank(owner); - systemConfigGlobal.addDevSigner(signer1, pcr0Hash1); - systemConfigGlobal.addDevSigner(signer2, pcr0Hash2); - systemConfigGlobal.addDevSigner(signer3, pcr0Hash3); + teeProverRegistry.addDevSigner(signer1, pcr0Hash1); + teeProverRegistry.addDevSigner(signer2, pcr0Hash2); + teeProverRegistry.addDevSigner(signer3, pcr0Hash3); vm.stopPrank(); - assertTrue(systemConfigGlobal.isValidSigner(signer1)); - assertTrue(systemConfigGlobal.isValidSigner(signer2)); - assertTrue(systemConfigGlobal.isValidSigner(signer3)); + assertTrue(teeProverRegistry.isValidSigner(signer1)); + assertTrue(teeProverRegistry.isValidSigner(signer2)); + assertTrue(teeProverRegistry.isValidSigner(signer3)); - assertEq(systemConfigGlobal.signerPCR0(signer1), pcr0Hash1); - assertEq(systemConfigGlobal.signerPCR0(signer2), pcr0Hash2); - assertEq(systemConfigGlobal.signerPCR0(signer3), pcr0Hash3); + assertEq(teeProverRegistry.signerPCR0(signer1), pcr0Hash1); + assertEq(teeProverRegistry.signerPCR0(signer2), pcr0Hash2); + assertEq(teeProverRegistry.signerPCR0(signer3), pcr0Hash3); } // ============ getRegisteredSigners Tests ============ function testGetRegisteredSignersEmpty() public view { - address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + address[] memory signers = teeProverRegistry.getRegisteredSigners(); assertEq(signers.length, 0); } @@ -407,9 +407,9 @@ contract SystemConfigGlobalTest is Test { bytes32 signerPcr0 = keccak256("pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); - address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + address[] memory signers = teeProverRegistry.getRegisteredSigners(); assertEq(signers.length, 1); assertEq(signers[0], signer); } @@ -419,14 +419,14 @@ contract SystemConfigGlobalTest is Test { bytes32 signerPcr0 = keccak256("pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); - assertEq(systemConfigGlobal.getRegisteredSigners().length, 1); + assertEq(teeProverRegistry.getRegisteredSigners().length, 1); vm.prank(owner); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); - address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + address[] memory signers = teeProverRegistry.getRegisteredSigners(); assertEq(signers.length, 0); } @@ -438,12 +438,12 @@ contract SystemConfigGlobalTest is Test { bytes32 sharedPcr0 = keccak256("pcr0"); vm.startPrank(owner); - systemConfigGlobal.addDevSigner(signer1, sharedPcr0); - systemConfigGlobal.addDevSigner(signer2, sharedPcr0); - systemConfigGlobal.addDevSigner(signer3, sharedPcr0); + teeProverRegistry.addDevSigner(signer1, sharedPcr0); + teeProverRegistry.addDevSigner(signer2, sharedPcr0); + teeProverRegistry.addDevSigner(signer3, sharedPcr0); vm.stopPrank(); - address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + address[] memory signers = teeProverRegistry.getRegisteredSigners(); assertEq(signers.length, 3); // Verify all three are present (order not guaranteed) @@ -469,29 +469,29 @@ contract SystemConfigGlobalTest is Test { // Register three signers vm.startPrank(owner); - systemConfigGlobal.addDevSigner(signer1, sharedPcr0); - systemConfigGlobal.addDevSigner(signer2, sharedPcr0); - systemConfigGlobal.addDevSigner(signer3, sharedPcr0); + teeProverRegistry.addDevSigner(signer1, sharedPcr0); + teeProverRegistry.addDevSigner(signer2, sharedPcr0); + teeProverRegistry.addDevSigner(signer3, sharedPcr0); vm.stopPrank(); - assertEq(systemConfigGlobal.getRegisteredSigners().length, 3); + assertEq(teeProverRegistry.getRegisteredSigners().length, 3); // Deregister the middle one vm.prank(manager); - systemConfigGlobal.deregisterSigner(signer2); + teeProverRegistry.deregisterSigner(signer2); - address[] memory signers = systemConfigGlobal.getRegisteredSigners(); + address[] memory signers = teeProverRegistry.getRegisteredSigners(); assertEq(signers.length, 2); // Mapping and set stay consistent for (uint256 i = 0; i < signers.length; i++) { - assertTrue(systemConfigGlobal.isValidSigner(signers[i])); + assertTrue(teeProverRegistry.isValidSigner(signers[i])); assertNotEq(signers[i], signer2); } // Deregistered signer not in mapping either - assertFalse(systemConfigGlobal.isValidSigner(signer2)); - assertEq(systemConfigGlobal.signerPCR0(signer2), bytes32(0)); + assertFalse(teeProverRegistry.isValidSigner(signer2)); + assertEq(teeProverRegistry.signerPCR0(signer2), bytes32(0)); } function testGetRegisteredSignersDeregisterIdempotent() public { @@ -499,15 +499,15 @@ contract SystemConfigGlobalTest is Test { bytes32 signerPcr0 = keccak256("pcr0"); vm.prank(owner); - systemConfigGlobal.addDevSigner(signer, signerPcr0); + teeProverRegistry.addDevSigner(signer, signerPcr0); vm.prank(owner); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); // Deregistering again should not revert and set should still be empty vm.prank(owner); - systemConfigGlobal.deregisterSigner(signer); + teeProverRegistry.deregisterSigner(signer); - assertEq(systemConfigGlobal.getRegisteredSigners().length, 0); + assertEq(teeProverRegistry.getRegisteredSigners().length, 0); } } diff --git a/test/multiproof/TEEVerifier.t.sol b/test/multiproof/TEEVerifier.t.sol index 3b19a0c55..87d6d2669 100644 --- a/test/multiproof/TEEVerifier.t.sol +++ b/test/multiproof/TEEVerifier.t.sol @@ -12,13 +12,13 @@ import { import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { MockAnchorStateRegistry } from "scripts/multiproof/mocks/MockAnchorStateRegistry.sol"; -import { DevSystemConfigGlobal } from "src/multiproof/mocks/MockDevSystemConfigGlobal.sol"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { DevTEEProverRegistry } from "src/multiproof/mocks/MockDevTEEProverRegistry.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; contract TEEVerifierTest is Test { TEEVerifier public verifier; - DevSystemConfigGlobal public systemConfigGlobal; + DevTEEProverRegistry public teeProverRegistry; ProxyAdmin public proxyAdmin; MockAnchorStateRegistry public anchorStateRegistry; @@ -39,28 +39,28 @@ contract TEEVerifierTest is Test { signerAddress = vm.addr(SIGNER_PRIVATE_KEY); // Deploy implementation (NitroEnclaveVerifier not needed for dev signer tests) - DevSystemConfigGlobal impl = new DevSystemConfigGlobal(INitroEnclaveVerifier(address(0))); + DevTEEProverRegistry impl = new DevTEEProverRegistry(INitroEnclaveVerifier(address(0))); // Deploy proxy admin proxyAdmin = new ProxyAdmin(address(this)); // Deploy proxy TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( - address(impl), address(proxyAdmin), abi.encodeCall(SystemConfigGlobal.initialize, (owner, owner)) + address(impl), address(proxyAdmin), abi.encodeCall(TEEProverRegistry.initialize, (owner, owner)) ); - systemConfigGlobal = DevSystemConfigGlobal(address(proxy)); + teeProverRegistry = DevTEEProverRegistry(address(proxy)); // Register the signer with PCR0 hash - systemConfigGlobal.addDevSigner(signerAddress, PCR0_HASH); + teeProverRegistry.addDevSigner(signerAddress, PCR0_HASH); // Set the proposer as valid - systemConfigGlobal.setProposer(PROPOSER, true); + teeProverRegistry.setProposer(PROPOSER, true); // Deploy TEEVerifier anchorStateRegistry = new MockAnchorStateRegistry(); verifier = new TEEVerifier( - SystemConfigGlobal(address(systemConfigGlobal)), IAnchorStateRegistry(address(anchorStateRegistry)) + TEEProverRegistry(address(teeProverRegistry)), IAnchorStateRegistry(address(anchorStateRegistry)) ); } @@ -150,6 +150,6 @@ contract TEEVerifierTest is Test { } function testConstants() public view { - assertEq(address(verifier.SYSTEM_CONFIG_GLOBAL()), address(systemConfigGlobal)); + assertEq(address(verifier.TEE_PROVER_REGISTRY()), address(teeProverRegistry)); } } diff --git a/test/setup/Setup.sol b/test/setup/Setup.sol index 0e9f1fe1d..d7eb18e44 100644 --- a/test/setup/Setup.sol +++ b/test/setup/Setup.sol @@ -68,7 +68,7 @@ import { IFeeSplitter } from "interfaces/L2/IFeeSplitter.sol"; import { IL1Withdrawer } from "interfaces/L2/IL1Withdrawer.sol"; import { ISuperchainRevSharesCalculator } from "interfaces/L2/ISuperchainRevSharesCalculator.sol"; import { IVerifier } from "interfaces/multiproof/IVerifier.sol"; -import { SystemConfigGlobal } from "src/multiproof/tee/SystemConfigGlobal.sol"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; /// @title Setup /// @dev This contact is responsible for setting up the contracts in state. It currently @@ -159,7 +159,7 @@ abstract contract Setup is FeatureFlags { IL1Withdrawer l1Withdrawer; ISuperchainRevSharesCalculator superchainRevSharesCalculator; IVerifier aggregateVerifier; - SystemConfigGlobal systemConfigGlobal; + TEEProverRegistry teeProverRegistry; /// @notice Indicates whether a test is running against a forked production network. function isForkTest() public view returns (bool) { @@ -299,7 +299,7 @@ abstract contract Setup is FeatureFlags { superchainProxyAdminOwner = superchainProxyAdmin.owner(); mips = IBigStepper(artifacts.mustGetAddress("MipsSingleton")); aggregateVerifier = IVerifier(artifacts.mustGetAddress("AggregateVerifier")); - systemConfigGlobal = SystemConfigGlobal(artifacts.mustGetAddress("SystemConfigGlobal")); + teeProverRegistry = TEEProverRegistry(artifacts.mustGetAddress("TEEProverRegistry")); if (deploy.cfg().useAltDA()) { dataAvailabilityChallenge = diff --git a/test/vendor/Initializable.t.sol b/test/vendor/Initializable.t.sol index 306eb2628..9a02d48d7 100644 --- a/test/vendor/Initializable.t.sol +++ b/test/vendor/Initializable.t.sol @@ -22,7 +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"; +import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; /// @title Initializer_Test /// @dev Ensures that the `initialize()` function on contracts cannot be called more than @@ -367,12 +367,12 @@ contract Initializer_Test is CommonTest { // AggregateVerifier uses a custom `bool initialized` instead of OpenZeppelin's `_initialized` // uint8, so it cannot be tested by this framework. It is excluded below. - // SystemConfigGlobalImpl + // TEEProverRegistryImpl contracts.push( InitializeableContract({ - name: "SystemConfigGlobalImpl", - target: address(systemConfigGlobal), - initCalldata: abi.encodeCall(SystemConfigGlobal.initialize, (address(0), address(0))) + name: "TEEProverRegistryImpl", + target: address(teeProverRegistry), + initCalldata: abi.encodeCall(TEEProverRegistry.initialize, (address(0), address(0))) }) ); } From b6c4689b8f814bf23fb915ac1d68a537d707ae4e Mon Sep 17 00:00:00 2001 From: roger-bai-coinbase Date: Sat, 14 Mar 2026 19:02:41 -0400 Subject: [PATCH 06/18] Add custom NitroEnclaveVerifier contract and update multiproof contracts (#206) * Add custom NitroEnclaveVerifier contract and update multiproof contracts - Add NitroEnclaveVerifier with ZK-based AWS Nitro attestation verification - Add tests for NitroEnclaveVerifier - Add proof submitter configurability to NitroEnclaveVerifier - Update TEEVerifier, MockVerifier, and deploy scripts accordingly - Update snapshots and semver-lock Made-with: Cursor * pr feedback * add INitroEnclaveVerifier * update license * add license to multiproof contracts * pr feedback * forge fmt --- interfaces/multiproof/IVerifier.sol | 1 - .../multiproof/tee/INitroEnclaveVerifier.sol | 416 +++++++++ scripts/deploy/DeployImplementations.s.sol | 4 +- scripts/multiproof/DeployDevNoNitro.s.sol | 4 +- scripts/multiproof/DeployDevWithNitro.s.sol | 4 +- snapshots/semver-lock.json | 12 +- src/multiproof/AggregateVerifier.sol | 2 +- .../mocks/MockDevTEEProverRegistry.sol | 4 +- src/multiproof/tee/NitroEnclaveVerifier.sol | 732 +++++++++++++++ src/multiproof/tee/TEEProverRegistry.sol | 2 +- test/multiproof/AggregateVerifier.t.sol | 2 +- test/multiproof/Challenge.t.sol | 2 +- test/multiproof/NitroEnclaveVerifier.t.sol | 836 ++++++++++++++++++ test/multiproof/Nullify.t.sol | 2 +- test/multiproof/TEEProverRegistry.t.sol | 6 +- test/multiproof/TEEVerifier.t.sol | 6 +- 16 files changed, 2003 insertions(+), 32 deletions(-) create mode 100644 interfaces/multiproof/tee/INitroEnclaveVerifier.sol create mode 100644 src/multiproof/tee/NitroEnclaveVerifier.sol create mode 100644 test/multiproof/NitroEnclaveVerifier.t.sol diff --git a/interfaces/multiproof/IVerifier.sol b/interfaces/multiproof/IVerifier.sol index e1ae29a54..4f5fbd38b 100644 --- a/interfaces/multiproof/IVerifier.sol +++ b/interfaces/multiproof/IVerifier.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.15; interface IVerifier { - /// @notice Verifies a proof. /// @param proofBytes The proof. /// @param imageId The image ID. diff --git a/interfaces/multiproof/tee/INitroEnclaveVerifier.sol b/interfaces/multiproof/tee/INitroEnclaveVerifier.sol new file mode 100644 index 000000000..a3edb91cf --- /dev/null +++ b/interfaces/multiproof/tee/INitroEnclaveVerifier.sol @@ -0,0 +1,416 @@ +//SPDX-License-Identifier: Apache2.0 +pragma solidity ^0.8.0; + +/// @dev Custom version of Automata's NitroEnclaveVerifier contract at +/// https://github.com/automata-network/aws-nitro-enclave-attestation/tree/26c90565cb009e6539643a0956f9502a12ade672 +/// +/// Differences from the upstream Automata contract: +/// - Removes verification-with-explicit-program-ID and Pico logic +/// - Errors and events moved to the implementation contract +/// - Adds new admin functions + +/** + * @dev Enumeration of supported zero-knowledge proof coprocessor types + * Used to specify which proving system to use for attestation verification + */ +enum ZkCoProcessorType { + Unknown, + // RISC Zero zkVM proving system + RiscZero, + // Succinct SP1 proving system + Succinct +} + +/** + * @dev Configuration parameters for a specific zero-knowledge coprocessor + * Contains all necessary identifiers and addresses for ZK proof verification + * + * Note: This struct stores the "latest" (active) program identifiers. + * Multiple versions can be supported simultaneously via the version management functions. + */ +struct ZkCoProcessorConfig { + // Latest program ID for single attestation verification + bytes32 verifierId; + // Latest program ID for batch/aggregated verification + bytes32 aggregatorId; + // Default ZK verifier contract address (can be overridden per route) + address zkVerifier; +} + +/** + * @dev Input structure for attestation report verification + * Contains the raw attestation data and trusted certificate chain length + */ +struct VerifierInput { + // Number of trusted certificates in the chain + uint8 trustedCertsPrefixLen; + // Raw AWS Nitro Enclave attestation report (COSE_Sign1 format) + bytes attestationReport; +} + +/** + * @dev Output structure containing verified attestation data and metadata + * This represents the journal/output from zero-knowledge proof verification + */ +struct VerifierJournal { + // Overall verification result status + VerificationResult result; + // Number of certificates that were trusted during verification + uint8 trustedCertsPrefixLen; + // Attestation timestamp (Unix timestamp in milliseconds) + uint64 timestamp; + // Array of certificate hashes in the chain (root to leaf) + bytes32[] certs; + // User-defined data embedded in the attestation + bytes userData; + // Cryptographic nonce used for replay protection + bytes nonce; + // Public key extracted from the attestation + bytes publicKey; + // Platform Configuration Registers (integrity measurements) + Pcr[] pcrs; + // AWS Nitro Enclave module identifier + string moduleId; +} + +/** + * @dev Public value (journal) structure for batch verification operations + * Contains the aggregated results of multiple attestation verifications + */ +struct BatchVerifierJournal { + // Verification key that was used for batch verification + bytes32 verifierVk; + // Array of verified attestation results + VerifierJournal[] outputs; +} + +/** + * @dev 48-byte data structure for storing PCR values + * Split into two parts due to Solidity's 32-byte word limitation + */ +struct Bytes48 { + bytes32 first; + bytes16 second; +} + +/** + * @dev Platform Configuration Register (PCR) entry + * PCRs contain cryptographic measurements of the enclave's runtime state + */ +struct Pcr { + // PCR index number (0-23 for AWS Nitro Enclaves) + uint64 index; + // 48-byte PCR measurement value (SHA-384 hash) + Bytes48 value; +} + +/** + * @dev Enumeration of possible attestation verification results + * Indicates the outcome of the verification process + */ +enum VerificationResult { + // Attestation successfully verified + Success, + // Root certificate is not in the trusted set + RootCertNotTrusted, + // One or more intermediate certificates are not trusted + IntermediateCertsNotTrusted, + // Attestation timestamp is outside acceptable range + InvalidTimestamp +} + +/** + * @title INitroEnclaveVerifier + * @dev Interface for AWS Nitro Enclave attestation verification using zero-knowledge proofs + * + * This interface defines the contract for verifying AWS Nitro Enclave attestation reports + * on-chain using zero-knowledge proof systems (RISC Zero or Succinct SP1). The verifier + * validates the cryptographic integrity of attestation reports while maintaining privacy + * and reducing gas costs through ZK proofs. + * + * Key features: + * - Single and batch attestation verification + * - Support for multiple ZK proving systems + * - Multi-version program support for seamless upgrades + * - Route-based verifier configuration + * - Certificate chain management and revocation + * - Timestamp validation with configurable tolerance + * - Platform Configuration Register (PCR) verification + */ +interface INitroEnclaveVerifier { + // ============ Query Functions ============ + + /** + * @dev Returns the maximum allowed time difference for attestation timestamp validation + * @return Maximum time difference in seconds between attestation time and current block time + */ + function maxTimeDiff() external view returns (uint64); + + /** + * @dev Returns the hash of the trusted root certificate + * @return Hash of the AWS Nitro Enclave root certificate + */ + function rootCert() external view returns (bytes32); + + /** + * @dev Returns the address of the proof submitter + * @return Address of the proof submitter + */ + function proofSubmitter() external view returns (address); + + /** + * @dev Retrieves the configuration for a specific coprocessor + * @param _zkCoProcessor Type of ZK coprocessor (RiscZero or Succinct) + * @return ZkCoProcessorConfig Configuration parameters including program IDs and verifier address + */ + function getZkConfig(ZkCoProcessorType _zkCoProcessor) external view returns (ZkCoProcessorConfig memory); + + /** + * @dev Returns all supported verifier program IDs for a coprocessor + * @param _zkCoProcessor Type of ZK coprocessor + * @return Array of all supported verifier program IDs + */ + function getVerifierIds(ZkCoProcessorType _zkCoProcessor) external view returns (bytes32[] memory); + + /** + * @dev Returns all supported aggregator program IDs for a coprocessor + * @param _zkCoProcessor Type of ZK coprocessor + * @return Array of all supported aggregator program IDs + */ + function getAggregatorIds(ZkCoProcessorType _zkCoProcessor) external view returns (bytes32[] memory); + + /** + * @dev Checks if a verifier program ID is in the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId Verifier program ID to check + * @return True if the ID is supported + */ + function isVerifierIdSupported(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external view returns (bool); + + /** + * @dev Checks if an aggregator program ID is in the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _aggregatorId Aggregator program ID to check + * @return True if the ID is supported + */ + function isAggregatorIdSupported( + ZkCoProcessorType _zkCoProcessor, + bytes32 _aggregatorId + ) + external + view + returns (bool); + + /** + * @dev Gets the verifier address for a specific route + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector + * @return Verifier address (route-specific or default fallback) + * + * Note: Reverts if the route is frozen + */ + function getZkVerifier(ZkCoProcessorType _zkCoProcessor, bytes4 _selector) external view returns (address); + + /** + * @dev Returns the verifierProofId for a given verifierId + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId The verifier program ID + * @return The corresponding verifierProofId + */ + function getVerifierProofId(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external view returns (bytes32); + + /** + * @dev Checks how many certificates in each report are trusted + * @param _report_certs Array of certificate chains, each containing certificate hashes + * @return Array indicating the number of trusted certificates in each chain + * + * For each certificate chain: + * - Validates that the first certificate matches the root certificate + * - Counts consecutive trusted certificates starting from the root + * - Returns the count of trusted certificates for each chain + */ + function checkTrustedIntermediateCerts(bytes32[][] calldata _report_certs) external view returns (uint8[] memory); + + // ============ Admin Functions ============ + + /** + * @dev Sets the trusted root certificate hash + * @param _rootCert Hash of the new root certificate + * + * Requirements: + * - Only callable by contract owner + */ + function setRootCert(bytes32 _rootCert) external; + + /** + * @dev Updates the maximum allowed time difference for attestation timestamp validation + * @param _maxTimeDiff New maximum time difference in seconds + * + * Requirements: + * - Only callable by contract owner + * - Must be greater than zero + */ + function setMaxTimeDiff(uint64 _maxTimeDiff) external; + + /** + * @dev Sets the proof submitter address + * @param _proofSubmitter The address of the proof submitter + * + * Requirements: + * - Only callable by contract owner + * - Address must not be zero + */ + function setProofSubmitter(address _proofSubmitter) external; + + /** + * @dev Configures the zero-knowledge verification parameters for a specific coprocessor + * @param _zkCoProcessor Type of ZK coprocessor (RiscZero or Succinct) + * @param _config Configuration parameters including program IDs and verifier address + * @param _verifierProofId The verifierProofId corresponding to the verifierId in config + * + * Requirements: + * - Only callable by contract owner + * - Must specify valid coprocessor type and configuration + */ + function setZkConfiguration( + ZkCoProcessorType _zkCoProcessor, + ZkCoProcessorConfig memory _config, + bytes32 _verifierProofId + ) + external; + + /** + * @dev Revokes a trusted intermediate certificate + * @param _certHash Hash of the certificate to revoke + * + * Requirements: + * - Only callable by contract owner + * - Certificate must exist in the trusted set + */ + function revokeCert(bytes32 _certHash) external; + + /** + * @dev Updates the verifier program ID, adding the new version to the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _newVerifierId New verifier program ID to set as latest + * @param _newVerifierProofId New verifier proof ID (used in batch verification) + * + * Requirements: + * - Only callable by contract owner + * - New ID must be different from current latest + */ + function updateVerifierId( + ZkCoProcessorType _zkCoProcessor, + bytes32 _newVerifierId, + bytes32 _newVerifierProofId + ) + external; + + /** + * @dev Updates the aggregator program ID, adding the new version to the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _newAggregatorId New aggregator program ID to set as latest + * + * Requirements: + * - Only callable by contract owner + * - New ID must be different from current latest + */ + function updateAggregatorId(ZkCoProcessorType _zkCoProcessor, bytes32 _newAggregatorId) external; + + /** + * @dev Removes a verifier program ID from the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId Verifier program ID to remove + * + * Requirements: + * - Only callable by contract owner + * - Cannot remove the currently active (latest) verifier ID + * - ID must exist in the supported set + */ + function removeVerifierId(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external; + + /** + * @dev Removes an aggregator program ID from the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _aggregatorId Aggregator program ID to remove + * + * Requirements: + * - Only callable by contract owner + * - Cannot remove the currently active (latest) aggregator ID + * - ID must exist in the supported set + */ + function removeAggregatorId(ZkCoProcessorType _zkCoProcessor, bytes32 _aggregatorId) external; + + /** + * @dev Adds a route-specific verifier override + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector (first 4 bytes of proof data) + * @param _verifier Address of the verifier contract for this route + * + * Requirements: + * - Only callable by contract owner + * - Route must not be frozen + * - Verifier address must not be zero + */ + function addVerifyRoute(ZkCoProcessorType _zkCoProcessor, bytes4 _selector, address _verifier) external; + + /** + * @dev Permanently freezes a verification route + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector to freeze + * + * Requirements: + * - Only callable by contract owner + * - Route must not already be frozen + * + * WARNING: This action is IRREVERSIBLE + */ + function freezeVerifyRoute(ZkCoProcessorType _zkCoProcessor, bytes4 _selector) external; + + // ============ Verification Functions ============ + + /** + * @dev Verifies a single attestation report using zero-knowledge proof + * @param output Encoded VerifierJournal containing the verification result + * @param zkCoprocessor Type of ZK coprocessor used to generate the proof + * @param proofBytes Zero-knowledge proof data for the attestation + * @return VerifierJournal containing the verification result and extracted data + * + * This function: + * 1. Verifies the ZK proof using the specified coprocessor + * 2. Decodes the verification result + * 3. Validates the certificate chain against trusted certificates + * 4. Checks timestamp validity within the allowed time difference + * 5. Caches newly discovered trusted certificates + * 6. Returns the complete verification result + */ + function verify( + bytes calldata output, + ZkCoProcessorType zkCoprocessor, + bytes calldata proofBytes + ) + external + returns (VerifierJournal memory); + + /** + * @dev Verifies multiple attestation reports in a single batch operation + * @param output Encoded BatchVerifierJournal containing aggregated verification results + * @param zkCoprocessor Type of ZK coprocessor used to generate the proof + * @param proofBytes Zero-knowledge proof data for batch verification + * @return Array of VerifierJournal results, one for each attestation in the batch + * + * This function: + * 1. Verifies the ZK proof using the specified coprocessor + * 2. Decodes the batch verification results + * 3. Validates each attestation's certificate chain and timestamp + * 4. Caches newly discovered trusted certificates + * 5. Returns the verification results for all attestations + */ + function batchVerify( + bytes calldata output, + ZkCoProcessorType zkCoprocessor, + bytes calldata proofBytes + ) + external + returns (VerifierJournal[] memory); +} diff --git a/scripts/deploy/DeployImplementations.s.sol b/scripts/deploy/DeployImplementations.s.sol index f38f2807a..38bb6691c 100644 --- a/scripts/deploy/DeployImplementations.s.sol +++ b/scripts/deploy/DeployImplementations.s.sol @@ -44,9 +44,7 @@ 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 { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; import { MockVerifier } from "src/multiproof/mocks/MockVerifier.sol"; import { TEEVerifier } from "src/multiproof/tee/TEEVerifier.sol"; diff --git a/scripts/multiproof/DeployDevNoNitro.s.sol b/scripts/multiproof/DeployDevNoNitro.s.sol index 7206759c7..4e7923058 100644 --- a/scripts/multiproof/DeployDevNoNitro.s.sol +++ b/scripts/multiproof/DeployDevNoNitro.s.sol @@ -52,9 +52,7 @@ pragma solidity 0.8.15; * ══════════════════════════════════════════════════════════════════════════════════ */ -import { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { Script } from "forge-std/Script.sol"; import { console2 as console } from "forge-std/console2.sol"; diff --git a/scripts/multiproof/DeployDevWithNitro.s.sol b/scripts/multiproof/DeployDevWithNitro.s.sol index add43ec6f..d812be401 100644 --- a/scripts/multiproof/DeployDevWithNitro.s.sol +++ b/scripts/multiproof/DeployDevWithNitro.s.sol @@ -86,9 +86,7 @@ pragma solidity 0.8.15; * ══════════════════════════════════════════════════════════════════════════════════ */ -import { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { Script } from "forge-std/Script.sol"; import { console2 as console } from "forge-std/console2.sol"; diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index 7316eb4b5..70c5bc813 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -241,19 +241,19 @@ }, "src/multiproof/AggregateVerifier.sol:AggregateVerifier": { "initCodeHash": "0xc3866b1d4515c9d7b0ac6679b182d836f79371402d9e649e301b24cf8ae8fade", - "sourceCodeHash": "0x3a079ea52a26c8c38fb0cb3e9a9ff6ec9648cf83786b65c0fc1161e949b8f7e0" + "sourceCodeHash": "0x98267b52a71222506c4893d6632dc5a36dd197a8d60de9a1f6578a80f7ebdf2d" }, "src/multiproof/AggregateVerifier.sol:AggregateVerifier:dispute": { "initCodeHash": "0xe28eaeecda21594f6db23bb70127daa2b7b71debe38ce65b598f28d78d2561eb", - "sourceCodeHash": "0x3a079ea52a26c8c38fb0cb3e9a9ff6ec9648cf83786b65c0fc1161e949b8f7e0" + "sourceCodeHash": "0x98267b52a71222506c4893d6632dc5a36dd197a8d60de9a1f6578a80f7ebdf2d" }, "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry": { - "initCodeHash": "0xee219c003a6af440b447e214e43d520e802001ae3d557262a7921ca3d57ebddf", - "sourceCodeHash": "0x8be9aea4bb16c89a10444da8ce324e3914a2419654a80542692757fbdc9a2f5c" + "initCodeHash": "0x09760f3a16c82db6a0e292a394d8a97cc34cc4aa799aeee9c1e064c9e8181050", + "sourceCodeHash": "0xae23e7c3e21c373d491a0e496ece54c63b5ad09171db1a011011eae3e2831c72" }, "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry:dispute": { - "initCodeHash": "0x8ae045f0121d2c63ab6f0a830be842aaf0445096bfabe29d85cfd9bd38b40565", - "sourceCodeHash": "0x8be9aea4bb16c89a10444da8ce324e3914a2419654a80542692757fbdc9a2f5c" + "initCodeHash": "0x7345fbc8139f09132ad1ee8432a0e30361e6e92b2cca18855cec81093f5f4ea7", + "sourceCodeHash": "0xae23e7c3e21c373d491a0e496ece54c63b5ad09171db1a011011eae3e2831c72" }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { "initCodeHash": "0xd65f1d604f979045a86d662e168cb7a867478da8a0ca294181872a90d209a66f", diff --git a/src/multiproof/AggregateVerifier.sol b/src/multiproof/AggregateVerifier.sol index 72499a1c8..43bac056e 100644 --- a/src/multiproof/AggregateVerifier.sol +++ b/src/multiproof/AggregateVerifier.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; // Optimism diff --git a/src/multiproof/mocks/MockDevTEEProverRegistry.sol b/src/multiproof/mocks/MockDevTEEProverRegistry.sol index 3d49434c8..759a102d0 100644 --- a/src/multiproof/mocks/MockDevTEEProverRegistry.sol +++ b/src/multiproof/mocks/MockDevTEEProverRegistry.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; diff --git a/src/multiproof/tee/NitroEnclaveVerifier.sol b/src/multiproof/tee/NitroEnclaveVerifier.sol new file mode 100644 index 000000000..e6c758b64 --- /dev/null +++ b/src/multiproof/tee/NitroEnclaveVerifier.sol @@ -0,0 +1,732 @@ +// SPDX-License-Identifier: Apache2.0 +pragma solidity ^0.8.0; + +import { Ownable } from "@solady/auth/Ownable.sol"; +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { + INitroEnclaveVerifier, + ZkCoProcessorType, + ZkCoProcessorConfig, + VerifierJournal, + BatchVerifierJournal, + VerificationResult +} from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; +import { + IRiscZeroVerifier +} from "lib/aws-nitro-enclave-attestation/contracts/lib/risc0-ethereum/contracts/src/IRiscZeroVerifier.sol"; +import { + ISP1Verifier +} from "lib/aws-nitro-enclave-attestation/contracts/lib/sp1-contracts/contracts/src/ISP1Verifier.sol"; + +/** + * @title NitroEnclaveVerifier + * @dev Implementation contract for AWS Nitro Enclave attestation verification using zero-knowledge proofs + * @dev Custom version of Automata's NitroEnclaveVerifier contract at + * https://github.com/automata-network/aws-nitro-enclave-attestation/tree/26c90565cb009e6539643a0956f9502a12ade672 + * + * Differences from the upstream Automata contract: + * - Verification of ZK proofs is restricted to an authorized proof submitter address + * - All privileged actions emit events for monitoring + * - Removes verification-with-explicit-program-ID and Pico logic + * + * This contract provides on-chain verification of AWS Nitro Enclave attestation reports by validating + * zero-knowledge proofs generated off-chain. It supports both single and batch verification modes + * and can work with multiple ZK proof systems (RISC Zero and Succinct SP1). + * + * Key features: + * - Certificate chain management with automatic caching of newly discovered certificates + * - Timestamp validation with configurable time tolerance + * - Certificate revocation capabilities for compromised intermediate certificates + * - Gas-efficient batch verification for multiple attestations + * - Support for both RISC Zero and SP1 proving systems + * + * Security considerations: + * - Only the contract owner can manage certificates and configurations + * - Root certificate is immutable once set (requires owner to change) + * - Intermediate certificates are automatically cached but can be revoked + * - Timestamp validation prevents replay attacks within the configured time window + */ +contract NitroEnclaveVerifier is Ownable, INitroEnclaveVerifier { + using EnumerableSet for EnumerableSet.Bytes32Set; + + /// @dev Sentinel address to indicate a route has been permanently frozen + address private constant FROZEN = address(0xdead); + + /// @dev Address that can submit proofs + address public proofSubmitter; + + /// @dev Configuration mapping for each supported ZK coprocessor type + mapping(ZkCoProcessorType => ZkCoProcessorConfig) public zkConfig; + + /// @dev Mapping of trusted intermediate certificate hashes (excludes root certificate) + mapping(bytes32 trustedCertHash => bool) public trustedIntermediateCerts; + + /// @dev Maximum allowed time difference in seconds for attestation timestamp validation + uint64 public maxTimeDiff; + + /// @dev Hash of the trusted AWS Nitro Enclave root certificate + bytes32 public rootCert; + + /// @dev Set of all supported verifier program IDs per coprocessor + mapping(ZkCoProcessorType => EnumerableSet.Bytes32Set) private _verifierIdSet; + + /// @dev Set of all supported aggregator program IDs per coprocessor + mapping(ZkCoProcessorType => EnumerableSet.Bytes32Set) private _aggregatorIdSet; + + /// @dev Route-specific verifier overrides (selector -> verifier address) + mapping(ZkCoProcessorType => mapping(bytes4 selector => address zkVerifier)) private _zkVerifierRoutes; + + /// @dev Mapping from verifierId to its corresponding verifierProofId representation + mapping(ZkCoProcessorType => mapping(bytes32 verifierId => bytes32 verifierProofId)) private _verifierProofIds; + + // ============ Custom Errors ============ + + /// @dev Error thrown when an unsupported or unknown ZK coprocessor type is used + error Unknown_Zk_Coprocessor(); + + /// @dev Error thrown when attempting to remove the currently active (latest) program ID + error CannotRemoveLatestProgramId(ZkCoProcessorType zkCoProcessor, bytes32 identifier); + + /// @dev Error thrown when a ZK route has been permanently frozen + error ZkRouteFrozen(ZkCoProcessorType zkCoProcessor, bytes4 selector); + + /// @dev Error thrown when no ZK verifier is configured for the coprocessor + error ZkVerifierNotConfigured(ZkCoProcessorType zkCoProcessor); + + /// @dev Thrown when a caller other than the authorized proof submitter calls verify or batchVerify + error CallerNotProofSubmitter(); + + /// @dev Thrown when a certificate hash is not found in the trusted intermediate certificates set + error CertificateNotFound(bytes32 certHash); + + /// @dev Thrown when a program ID argument is bytes32(0) + error ZeroProgramId(); + + /// @dev Thrown when attempting to set a program ID that is already the latest + error ProgramIdAlreadyLatest(ZkCoProcessorType zkCoProcessor, bytes32 identifier); + + /// @dev Thrown when attempting to remove or operate on a program ID that does not exist in the set + error ProgramIdNotFound(ZkCoProcessorType zkCoProcessor, bytes32 identifier); + + /// @dev Thrown when a zero address is provided where a verifier address is required + error ZeroVerifierAddress(); + + /// @dev Thrown when a zero address is provided for the proof submitter + error ZeroProofSubmitter(); + + /// @dev Thrown when the batch journal's verifier VK does not match the expected verifier proof ID + error VerifierVkMismatch(bytes32 expected, bytes32 actual); + + /// @dev Thrown when the first certificate in a chain does not match the stored root certificate + error RootCertMismatch(bytes32 expected, bytes32 actual); + + /// @dev Thrown when calling verifyWithProgramId or batchVerifyWithProgramId, which are intentionally disabled + error NotImplemented(); + + /// @dev Error thrown when a zero maxTimeDiff is provided + error ZeroMaxTimeDiff(); + + // ============ Events ============ + + /// @dev Emitted when a new verifier program ID is added/updated + event VerifierIdUpdated(ZkCoProcessorType indexed zkCoProcessor, bytes32 indexed newId, bytes32 newProofId); + + /// @dev Emitted when a new aggregator program ID is added/updated + event AggregatorIdUpdated(ZkCoProcessorType indexed zkCoProcessor, bytes32 indexed newId); + + /// @dev Emitted when a program ID is removed from the supported set + event ProgramIdRemoved(ZkCoProcessorType indexed zkCoProcessor, bytes32 indexed programId, bool isAggregator); + + /// @dev Emitted when a route-specific verifier is added + event ZkRouteAdded(ZkCoProcessorType indexed zkCoProcessor, bytes4 indexed selector, address verifier); + + /// @dev Emitted when a route is permanently frozen + event ZkRouteWasFrozen(ZkCoProcessorType indexed zkCoProcessor, bytes4 indexed selector); + + /// @dev Emitted when the proof of attestation has been successfully verified + event AttestationSubmitted(VerificationResult result, ZkCoProcessorType zkCoProcessor, bytes output); + + /// @dev Emitted when a batched proof has been successfully verified; encodedBatched = abi.encode(VerifierJournal[]) + event BatchAttestationSubmitted(bytes32 verifierId, ZkCoProcessorType zkCoProcessor, bytes encodedBatch); + + /// @dev Event emitted when the proof submitter address is changed + event ProofSubmitterChanged(address newProofSubmitter); + + /// @dev Event emitted when the root certificate is changed + event RootCertChanged(bytes32 newRootCert); + + /// @dev Event emitted when the ZK configuration is updated + event ZKConfigurationUpdated(ZkCoProcessorType zkCoProcessor, ZkCoProcessorConfig config, bytes32 verifierProofId); + + /// @dev Event emitted when a certificate is revoked + event CertRevoked(bytes32 certHash); + + /// @dev Event emitted when the maximum time difference is updated + event MaxTimeDiffUpdated(uint64 newMaxTimeDiff); + + /** + * @dev Initializes the contract with owner, time tolerance and initial trusted certificates + * @param _owner Address to be set as the contract owner + * @param _maxTimeDiff Maximum time difference in seconds for timestamp validation + * @param _initializeTrustedCerts Array of initial trusted intermediate certificate hashes + * + * Sets the provided address as the contract owner and initializes the trusted certificate set. + * The root certificate must be set separately after deployment. + */ + constructor(address _owner, uint64 _maxTimeDiff, bytes32[] memory _initializeTrustedCerts) { + if (_maxTimeDiff == 0) revert ZeroMaxTimeDiff(); + maxTimeDiff = _maxTimeDiff; + for (uint256 i = 0; i < _initializeTrustedCerts.length; i++) { + trustedIntermediateCerts[_initializeTrustedCerts[i]] = true; + } + _initializeOwner(_owner); + } + + // ============ Query Functions ============ + + /** + * @dev Retrieves the configuration for a specific coprocessor + * @param _zkCoProcessor Type of ZK coprocessor (RiscZero or Succinct) + * @return ZkCoProcessorConfig Configuration parameters including program IDs and verifier address + */ + function getZkConfig(ZkCoProcessorType _zkCoProcessor) external view returns (ZkCoProcessorConfig memory) { + return zkConfig[_zkCoProcessor]; + } + + /** + * @dev Returns all supported verifier program IDs for a coprocessor + * @param _zkCoProcessor Type of ZK coprocessor + * @return Array of all supported verifier program IDs + */ + function getVerifierIds(ZkCoProcessorType _zkCoProcessor) external view returns (bytes32[] memory) { + return _verifierIdSet[_zkCoProcessor].values(); + } + + /** + * @dev Returns all supported aggregator program IDs for a coprocessor + * @param _zkCoProcessor Type of ZK coprocessor + * @return Array of all supported aggregator program IDs + */ + function getAggregatorIds(ZkCoProcessorType _zkCoProcessor) external view returns (bytes32[] memory) { + return _aggregatorIdSet[_zkCoProcessor].values(); + } + + /** + * @dev Checks if a verifier program ID is in the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId Verifier program ID to check + * @return True if the ID is supported + */ + function isVerifierIdSupported(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external view returns (bool) { + return _verifierIdSet[_zkCoProcessor].contains(_verifierId); + } + + /** + * @dev Checks if an aggregator program ID is in the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _aggregatorId Aggregator program ID to check + * @return True if the ID is supported + */ + function isAggregatorIdSupported( + ZkCoProcessorType _zkCoProcessor, + bytes32 _aggregatorId + ) + external + view + returns (bool) + { + return _aggregatorIdSet[_zkCoProcessor].contains(_aggregatorId); + } + + /** + * @dev Gets the verifier address for a specific route + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector + * @return Verifier address (route-specific or default fallback) + */ + function getZkVerifier(ZkCoProcessorType _zkCoProcessor, bytes4 _selector) external view returns (address) { + address verifier = _zkVerifierRoutes[_zkCoProcessor][_selector]; + + if (verifier == FROZEN) { + revert ZkRouteFrozen(_zkCoProcessor, _selector); + } + + if (verifier == address(0)) { + return zkConfig[_zkCoProcessor].zkVerifier; + } + + return verifier; + } + + /** + * @dev Returns the verifierProofId for a given verifierId + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId The verifier program ID + * @return The corresponding verifierProofId + */ + function getVerifierProofId(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external view returns (bytes32) { + return _verifierProofIds[_zkCoProcessor][_verifierId]; + } + + /** + * @dev Checks the prefix length of trusted certificates in each provided certificate chain for reports + * @param _report_certs Array of certificate chains, each containing certificate hashes + * @return Array indicating the prefix length of trusted certificates in each chain + * + * For each certificate chain: + * 1. Validates that the first certificate matches the stored root certificate + * 2. Counts consecutive trusted certificates starting from the root + * 3. Stops counting when an untrusted certificate is encountered + * + * This function is used to pre-validate certificate chains before generating proofs, + * helping to optimize the proving process by determining trusted certificate lengths. + * Usually called from off-chain + */ + function checkTrustedIntermediateCerts(bytes32[][] calldata _report_certs) public view returns (uint8[] memory) { + uint8[] memory results = new uint8[](_report_certs.length); + bytes32 rootCertHash = rootCert; + for (uint256 i = 0; i < _report_certs.length; i++) { + bytes32[] calldata certs = _report_certs[i]; + uint8 trustedCertPrefixLen = 1; + if (certs[0] != rootCertHash) { + revert RootCertMismatch(rootCertHash, certs[0]); + } + for (uint256 j = 1; j < certs.length; j++) { + if (!trustedIntermediateCerts[certs[j]]) { + break; + } + trustedCertPrefixLen += 1; + } + results[i] = trustedCertPrefixLen; + } + return results; + } + + // ============ Admin Functions ============ + + /** + * @dev Sets the trusted root certificate hash + * @param _rootCert Hash of the AWS Nitro Enclave root certificate + * + * Requirements: + * - Only callable by contract owner + * + * The root certificate serves as the trust anchor for all certificate chain validations. + * This should be set to the hash of AWS's root certificate for Nitro Enclaves. + */ + function setRootCert(bytes32 _rootCert) external onlyOwner { + rootCert = _rootCert; + emit RootCertChanged(_rootCert); + } + + /** + * @dev Updates the maximum allowed time difference for attestation timestamp validation + * @param _maxTimeDiff New maximum time difference in seconds + * + * Requirements: + * - Only callable by contract owner + * - Must be greater than zero + */ + function setMaxTimeDiff(uint64 _maxTimeDiff) external onlyOwner { + if (_maxTimeDiff == 0) revert ZeroMaxTimeDiff(); + maxTimeDiff = _maxTimeDiff; + emit MaxTimeDiffUpdated(_maxTimeDiff); + } + + /** + * @dev Configures zero-knowledge verification parameters for a specific coprocessor + * @param _zkCoProcessor Type of ZK coprocessor (RiscZero or Succinct) + * @param _config Configuration parameters including program IDs and verifier address + * @param _verifierProofId The verifierProofId corresponding to the verifierId in config + * + * Requirements: + * - Only callable by contract owner + * + * This function sets up the necessary parameters for ZK proof verification: + * - verifierId: Program ID for single attestation verification + * - aggregatorId: Program ID for batch/aggregated verification + * - zkVerifier: Address of the deployed ZK verifier contract + * + * Note: Program IDs are automatically added to the supported version sets + * The verifierProofId is stored in a separate mapping (verifierId => verifierProofId) + */ + function setZkConfiguration( + ZkCoProcessorType _zkCoProcessor, + ZkCoProcessorConfig memory _config, + bytes32 _verifierProofId + ) + external + onlyOwner + { + zkConfig[_zkCoProcessor] = _config; + + // Auto-add program IDs to the version sets and store verifierProofId mapping + if (_config.verifierId != bytes32(0)) { + _verifierIdSet[_zkCoProcessor].add(_config.verifierId); + _verifierProofIds[_zkCoProcessor][_config.verifierId] = _verifierProofId; + } + if (_config.aggregatorId != bytes32(0)) { + _aggregatorIdSet[_zkCoProcessor].add(_config.aggregatorId); + } + emit ZKConfigurationUpdated(_zkCoProcessor, _config, _verifierProofId); + } + + /** + * @dev Revokes a trusted intermediate certificate + * @param _certHash Hash of the certificate to revoke + * + * Requirements: + * - Only callable by contract owner + * - Certificate must exist in the trusted intermediate certificates set + * + * This function allows the owner to revoke compromised intermediate certificates + * without affecting the root certificate or other trusted certificates. + */ + function revokeCert(bytes32 _certHash) external onlyOwner { + if (!trustedIntermediateCerts[_certHash]) { + revert CertificateNotFound(_certHash); + } + delete trustedIntermediateCerts[_certHash]; + emit CertRevoked(_certHash); + } + + /** + * @dev Updates the verifier program ID, adding the new version to the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _newVerifierId New verifier program ID to set as latest + * @param _newVerifierProofId New verifier proof ID (stored in mapping, used in batch verification) + */ + function updateVerifierId( + ZkCoProcessorType _zkCoProcessor, + bytes32 _newVerifierId, + bytes32 _newVerifierProofId + ) + external + onlyOwner + { + if (_newVerifierId == bytes32(0)) revert ZeroProgramId(); + if (zkConfig[_zkCoProcessor].verifierId == _newVerifierId) { + revert ProgramIdAlreadyLatest(_zkCoProcessor, _newVerifierId); + } + + zkConfig[_zkCoProcessor].verifierId = _newVerifierId; + _verifierIdSet[_zkCoProcessor].add(_newVerifierId); + _verifierProofIds[_zkCoProcessor][_newVerifierId] = _newVerifierProofId; + + emit VerifierIdUpdated(_zkCoProcessor, _newVerifierId, _newVerifierProofId); + } + + /** + * @dev Updates the aggregator program ID, adding the new version to the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _newAggregatorId New aggregator program ID to set as latest + */ + function updateAggregatorId(ZkCoProcessorType _zkCoProcessor, bytes32 _newAggregatorId) external onlyOwner { + if (_newAggregatorId == bytes32(0)) revert ZeroProgramId(); + if (zkConfig[_zkCoProcessor].aggregatorId == _newAggregatorId) { + revert ProgramIdAlreadyLatest(_zkCoProcessor, _newAggregatorId); + } + + zkConfig[_zkCoProcessor].aggregatorId = _newAggregatorId; + _aggregatorIdSet[_zkCoProcessor].add(_newAggregatorId); + + emit AggregatorIdUpdated(_zkCoProcessor, _newAggregatorId); + } + + /** + * @dev Removes a verifier program ID from the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _verifierId Verifier program ID to remove + */ + function removeVerifierId(ZkCoProcessorType _zkCoProcessor, bytes32 _verifierId) external onlyOwner { + if (!_verifierIdSet[_zkCoProcessor].contains(_verifierId)) { + revert ProgramIdNotFound(_zkCoProcessor, _verifierId); + } + + // Cannot remove the latest verifier ID - must update to a new one first + if (zkConfig[_zkCoProcessor].verifierId == _verifierId) { + revert CannotRemoveLatestProgramId(_zkCoProcessor, _verifierId); + } + + _verifierIdSet[_zkCoProcessor].remove(_verifierId); + delete _verifierProofIds[_zkCoProcessor][_verifierId]; + emit ProgramIdRemoved(_zkCoProcessor, _verifierId, false); + } + + /** + * @dev Removes an aggregator program ID from the supported set + * @param _zkCoProcessor Type of ZK coprocessor + * @param _aggregatorId Aggregator program ID to remove + */ + function removeAggregatorId(ZkCoProcessorType _zkCoProcessor, bytes32 _aggregatorId) external onlyOwner { + if (!_aggregatorIdSet[_zkCoProcessor].contains(_aggregatorId)) { + revert ProgramIdNotFound(_zkCoProcessor, _aggregatorId); + } + + // Cannot remove the latest aggregator ID - must update to a new one first + if (zkConfig[_zkCoProcessor].aggregatorId == _aggregatorId) { + revert CannotRemoveLatestProgramId(_zkCoProcessor, _aggregatorId); + } + + _aggregatorIdSet[_zkCoProcessor].remove(_aggregatorId); + emit ProgramIdRemoved(_zkCoProcessor, _aggregatorId, true); + } + + /** + * @dev Adds a route-specific verifier override + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector (first 4 bytes of proof data) + * @param _verifier Address of the verifier contract for this route + */ + function addVerifyRoute(ZkCoProcessorType _zkCoProcessor, bytes4 _selector, address _verifier) external onlyOwner { + if (_verifier == address(0)) revert ZeroVerifierAddress(); + + if (_zkVerifierRoutes[_zkCoProcessor][_selector] == FROZEN) { + revert ZkRouteFrozen(_zkCoProcessor, _selector); + } + + _zkVerifierRoutes[_zkCoProcessor][_selector] = _verifier; + emit ZkRouteAdded(_zkCoProcessor, _selector, _verifier); + } + + /** + * @dev Permanently freezes a verification route + * @param _zkCoProcessor Type of ZK coprocessor + * @param _selector Proof selector to freeze + * + * WARNING: This action is IRREVERSIBLE + */ + function freezeVerifyRoute(ZkCoProcessorType _zkCoProcessor, bytes4 _selector) external onlyOwner { + address currentVerifier = _zkVerifierRoutes[_zkCoProcessor][_selector]; + + if (currentVerifier == FROZEN) { + revert ZkRouteFrozen(_zkCoProcessor, _selector); + } + + _zkVerifierRoutes[_zkCoProcessor][_selector] = FROZEN; + emit ZkRouteWasFrozen(_zkCoProcessor, _selector); + } + + /** + * @dev Sets the proof submitter address + * @param _proofSubmitter The address of the proof submitter + * + * Requirements: + * - Only callable by contract owner + * - Address must not be zero + */ + function setProofSubmitter(address _proofSubmitter) external onlyOwner { + if (_proofSubmitter == address(0)) revert ZeroProofSubmitter(); + proofSubmitter = _proofSubmitter; + emit ProofSubmitterChanged(_proofSubmitter); + } + + // ============ Verification Functions ============ + + /** + * @dev Verifies a single attestation report using zero-knowledge proof + * @param output Encoded VerifierJournal containing the verification result + * @param zkCoprocessor Type of ZK coprocessor used to generate the proof + * @param proofBytes Zero-knowledge proof data for the attestation + * @return journal VerifierJournal containing the verification result and extracted data + * + * This function performs end-to-end verification of a single attestation: + * 1. Retrieves the single verification program ID from configuration + * 2. Verifies the zero-knowledge proof using the specified coprocessor + * 3. Decodes the verification journal from the output + * 4. Validates the journal through comprehensive checks + * 5. Returns the final verification result + * + * The returned journal contains all extracted attestation data including: + * - Verification status and any error conditions + * - Certificate chain information and trust levels + * - User data, nonce, and public key from the attestation + * - Platform Configuration Registers (PCRs) for integrity measurement + * - Module ID and timestamp information + */ + function verify( + bytes calldata output, + ZkCoProcessorType zkCoprocessor, + bytes calldata proofBytes + ) + external + returns (VerifierJournal memory journal) + { + if (msg.sender != proofSubmitter) revert CallerNotProofSubmitter(); + bytes32 programId = zkConfig[zkCoprocessor].verifierId; + _verifyZk(zkCoprocessor, programId, output, proofBytes); + journal = abi.decode(output, (VerifierJournal)); + journal = _verifyJournal(journal); + emit AttestationSubmitted(journal.result, zkCoprocessor, output); + } + + /** + * @dev Verifies multiple attestation reports in a single batch operation + * @param output Encoded BatchVerifierJournal containing aggregated verification results + * @param zkCoprocessor Type of ZK coprocessor used to generate the proof + * @param proofBytes Zero-knowledge proof data for batch verification + * @return results Array of VerifierJournal results, one for each attestation in the batch + * + * This function provides gas-efficient batch verification by: + * 1. Using the aggregator program ID for ZK proof verification + * 2. Validating the batch verifier key matches the expected value + * 3. Processing each individual attestation through standard validation + * 4. Returning comprehensive results for all attestations + * + * Batch verification is recommended when processing multiple attestations + * as it significantly reduces gas costs compared to individual verifications. + */ + function batchVerify( + bytes calldata output, + ZkCoProcessorType zkCoprocessor, + bytes calldata proofBytes + ) + external + returns (VerifierJournal[] memory results) + { + if (msg.sender != proofSubmitter) revert CallerNotProofSubmitter(); + bytes32 aggregatorId = zkConfig[zkCoprocessor].aggregatorId; + bytes32 verifierId = zkConfig[zkCoprocessor].verifierId; + bytes32 verifierProofId = _verifierProofIds[zkCoprocessor][verifierId]; + + _verifyZk(zkCoprocessor, aggregatorId, output, proofBytes); + BatchVerifierJournal memory batchJournal = abi.decode(output, (BatchVerifierJournal)); + if (batchJournal.verifierVk != verifierProofId) { + revert VerifierVkMismatch(verifierProofId, batchJournal.verifierVk); + } + uint256 n = batchJournal.outputs.length; + results = new VerifierJournal[](n); + for (uint256 i = 0; i < n; i++) { + results[i] = _verifyJournal(batchJournal.outputs[i]); + } + emit BatchAttestationSubmitted(verifierId, zkCoprocessor, abi.encode(results)); + } + + // ============ Internal Functions ============ + + /** + * @dev Internal function to cache newly discovered trusted certificates + * @param journal Verification journal containing certificate chain information + * + * This function automatically adds any certificates beyond the trusted length + * to the trusted intermediate certificates set. This optimizes future verifications + * by expanding the known trusted certificate set based on successful verifications. + */ + function _cacheNewCert(VerifierJournal memory journal) internal { + for (uint256 i = journal.trustedCertsPrefixLen; i < journal.certs.length; i++) { + bytes32 certHash = journal.certs[i]; + trustedIntermediateCerts[certHash] = true; + } + } + + /** + * @dev Internal function to verify and validate a journal entry + * @param journal Verification journal to validate + * @return Updated journal with final verification result + * + * This function performs comprehensive validation: + * 1. Checks if the initial ZK verification was successful + * 2. Validates the root certificate matches the trusted root + * 3. Ensures all trusted certificates are still valid (not revoked) + * 4. Validates the attestation timestamp is within acceptable range + * 5. Caches newly discovered certificates for future use + * + * The timestamp validation converts milliseconds to seconds and checks: + * - Attestation is not too old (timestamp + maxTimeDiff >= block.timestamp) + * - Attestation is not from the future (timestamp <= block.timestamp) + */ + function _verifyJournal(VerifierJournal memory journal) internal returns (VerifierJournal memory) { + if (journal.result != VerificationResult.Success) { + return journal; + } + if (journal.trustedCertsPrefixLen == 0) { + journal.result = VerificationResult.RootCertNotTrusted; + return journal; + } + // Check every trusted certificate to ensure none have been revoked + for (uint256 i = 0; i < journal.trustedCertsPrefixLen; i++) { + bytes32 certHash = journal.certs[i]; + if (i == 0) { + if (certHash != rootCert) { + journal.result = VerificationResult.RootCertNotTrusted; + return journal; + } + continue; + } + if (!trustedIntermediateCerts[certHash]) { + journal.result = VerificationResult.IntermediateCertsNotTrusted; + return journal; + } + } + uint64 timestamp = journal.timestamp / 1000; + if (timestamp + maxTimeDiff < block.timestamp || timestamp > block.timestamp) { + journal.result = VerificationResult.InvalidTimestamp; + return journal; + } + _cacheNewCert(journal); + return journal; + } + + /** + * @dev Internal function to verify zero-knowledge proofs using the appropriate coprocessor + * @param zkCoprocessor Type of ZK coprocessor (RiscZero or Succinct) + * @param programId Program identifier for the verification program + * @param output Encoded output data to verify + * @param proofBytes Zero-knowledge proof data + */ + function _verifyZk( + ZkCoProcessorType zkCoprocessor, + bytes32 programId, + bytes calldata output, + bytes calldata proofBytes + ) + internal + view + { + // Resolve the verifier address (route-specific or default) + address verifier = _resolveZkVerifier(zkCoprocessor, proofBytes); + + if (zkCoprocessor == ZkCoProcessorType.RiscZero) { + IRiscZeroVerifier(verifier).verify(proofBytes, programId, sha256(output)); + } else if (zkCoprocessor == ZkCoProcessorType.Succinct) { + ISP1Verifier(verifier).verifyProof(programId, output, proofBytes); + } else { + revert Unknown_Zk_Coprocessor(); + } + } + + /** + * @dev Internal function to resolve the ZK verifier address based on route configuration + * @param zkCoprocessor Type of ZK coprocessor + * @param proofBytes Proof data (selector extracted from first 4 bytes) + * @return Resolved verifier address + */ + function _resolveZkVerifier( + ZkCoProcessorType zkCoprocessor, + bytes calldata proofBytes + ) + internal + view + returns (address) + { + bytes4 selector = bytes4(proofBytes[0:4]); + address verifier = _zkVerifierRoutes[zkCoprocessor][selector]; + + // Check if route is frozen + if (verifier == FROZEN) { + revert ZkRouteFrozen(zkCoprocessor, selector); + } + + // Fall back to default verifier if no route-specific one configured + if (verifier == address(0)) { + verifier = zkConfig[zkCoprocessor].zkVerifier; + } + + // Ensure verifier is configured + if (verifier == address(0)) { + revert ZkVerifierNotConfigured(zkCoprocessor); + } + + return verifier; + } +} diff --git a/src/multiproof/tee/TEEProverRegistry.sol b/src/multiproof/tee/TEEProverRegistry.sol index ae3dd38f2..616bb5140 100644 --- a/src/multiproof/tee/TEEProverRegistry.sol +++ b/src/multiproof/tee/TEEProverRegistry.sol @@ -8,7 +8,7 @@ import { VerificationResult, Pcr, Bytes48 -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +} from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { OwnableManagedUpgradeable } from "lib/op-enclave/contracts/src/OwnableManagedUpgradeable.sol"; import { ISemver } from "interfaces/universal/ISemver.sol"; import { EnumerableSetLib } from "@solady-v0.0.245/utils/EnumerableSetLib.sol"; diff --git a/test/multiproof/AggregateVerifier.t.sol b/test/multiproof/AggregateVerifier.t.sol index a60f081ee..0679267e2 100644 --- a/test/multiproof/AggregateVerifier.t.sol +++ b/test/multiproof/AggregateVerifier.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { BadExtraData, GameNotResolved } from "src/dispute/lib/Errors.sol"; diff --git a/test/multiproof/Challenge.t.sol b/test/multiproof/Challenge.t.sol index aefe5a4de..661b68f15 100644 --- a/test/multiproof/Challenge.t.sol +++ b/test/multiproof/Challenge.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { ClaimAlreadyResolved } from "src/dispute/lib/Errors.sol"; diff --git a/test/multiproof/NitroEnclaveVerifier.t.sol b/test/multiproof/NitroEnclaveVerifier.t.sol new file mode 100644 index 000000000..604e555b2 --- /dev/null +++ b/test/multiproof/NitroEnclaveVerifier.t.sol @@ -0,0 +1,836 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import { Test } from "forge-std/Test.sol"; + +import { + ZkCoProcessorType, + ZkCoProcessorConfig, + VerifierJournal, + BatchVerifierJournal, + VerificationResult, + Pcr +} from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; + +import { NitroEnclaveVerifier } from "src/multiproof/tee/NitroEnclaveVerifier.sol"; + +contract NitroEnclaveVerifierTest is Test { + NitroEnclaveVerifier public verifier; + + address public owner; + address public submitter; + address public mockRiscZeroVerifier; + address public mockSP1Verifier; + + bytes32 public constant ROOT_CERT = keccak256("root-cert"); + bytes32 public constant INTERMEDIATE_CERT_1 = keccak256("intermediate-cert-1"); + bytes32 public constant INTERMEDIATE_CERT_2 = keccak256("intermediate-cert-2"); + bytes32 public constant VERIFIER_ID = keccak256("verifier-id"); + bytes32 public constant AGGREGATOR_ID = keccak256("aggregator-id"); + bytes32 public constant VERIFIER_PROOF_ID = keccak256("verifier-proof-id"); + + uint64 public constant MAX_TIME_DIFF = 3600; // 1 hour + + // Realistic timestamp so timestamp validation tests work correctly + uint256 internal constant REALISTIC_TIMESTAMP = 1_700_000_000; + + function setUp() public { + vm.warp(REALISTIC_TIMESTAMP); + + owner = address(this); + submitter = makeAddr("submitter"); + mockRiscZeroVerifier = makeAddr("mock-riscZero-verifier"); + mockSP1Verifier = makeAddr("mock-sp1-verifier"); + + bytes32[] memory trustedCerts = new bytes32[](1); + trustedCerts[0] = INTERMEDIATE_CERT_1; + + verifier = new NitroEnclaveVerifier(owner, MAX_TIME_DIFF, trustedCerts); + verifier.setRootCert(ROOT_CERT); + verifier.setProofSubmitter(submitter); + } + + // ============ Constructor Tests ============ + + function testConstructorSetsOwner() public view { + assertEq(verifier.owner(), owner); + } + + function testConstructorSetsMaxTimeDiff() public view { + assertEq(verifier.maxTimeDiff(), MAX_TIME_DIFF); + } + + function testConstructorSetsTrustedCerts() public view { + assertTrue(verifier.trustedIntermediateCerts(INTERMEDIATE_CERT_1)); + assertFalse(verifier.trustedIntermediateCerts(INTERMEDIATE_CERT_2)); + } + + function testConstructorRevertsIfZeroMaxTimeDiff() public { + bytes32[] memory certs = new bytes32[](0); + vm.expectRevert(NitroEnclaveVerifier.ZeroMaxTimeDiff.selector); + new NitroEnclaveVerifier(owner, 0, certs); + } + + // ============ setRootCert Tests ============ + + function testSetRootCert() public { + bytes32 newRoot = keccak256("new-root"); + verifier.setRootCert(newRoot); + assertEq(verifier.rootCert(), newRoot); + } + + function testSetRootCertRevertsIfNotOwner() public { + vm.prank(submitter); + vm.expectRevert(); + verifier.setRootCert(keccak256("bad")); + } + + // ============ setMaxTimeDiff Tests ============ + + function testSetMaxTimeDiff() public { + uint64 newTimeDiff = 7200; + verifier.setMaxTimeDiff(newTimeDiff); + assertEq(verifier.maxTimeDiff(), newTimeDiff); + } + + function testSetMaxTimeDiffRevertsIfZero() public { + vm.expectRevert(NitroEnclaveVerifier.ZeroMaxTimeDiff.selector); + verifier.setMaxTimeDiff(0); + } + + function testSetMaxTimeDiffRevertsIfNotOwner() public { + vm.prank(submitter); + vm.expectRevert(); + verifier.setMaxTimeDiff(7200); + } + + // ============ setProofSubmitter Tests ============ + + function testSetProofSubmitter() public { + address newSubmitter = makeAddr("new-submitter"); + verifier.setProofSubmitter(newSubmitter); + assertEq(verifier.proofSubmitter(), newSubmitter); + } + + function testSetProofSubmitterRevertsIfZeroAddress() public { + vm.expectRevert(NitroEnclaveVerifier.ZeroProofSubmitter.selector); + verifier.setProofSubmitter(address(0)); + } + + function testSetProofSubmitterRevertsIfNotOwner() public { + vm.prank(submitter); + vm.expectRevert(); + verifier.setProofSubmitter(makeAddr("anyone")); + } + + // ============ setZkConfiguration Tests ============ + + function testSetZkConfiguration() public { + ZkCoProcessorConfig memory config = ZkCoProcessorConfig({ + verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: mockRiscZeroVerifier + }); + + verifier.setZkConfiguration(ZkCoProcessorType.RiscZero, config, VERIFIER_PROOF_ID); + + ZkCoProcessorConfig memory stored = verifier.getZkConfig(ZkCoProcessorType.RiscZero); + assertEq(stored.verifierId, VERIFIER_ID); + assertEq(stored.aggregatorId, AGGREGATOR_ID); + assertEq(stored.zkVerifier, mockRiscZeroVerifier); + + assertTrue(verifier.isVerifierIdSupported(ZkCoProcessorType.RiscZero, VERIFIER_ID)); + assertTrue(verifier.isAggregatorIdSupported(ZkCoProcessorType.RiscZero, AGGREGATOR_ID)); + assertEq(verifier.getVerifierProofId(ZkCoProcessorType.RiscZero, VERIFIER_ID), VERIFIER_PROOF_ID); + } + + function testSetZkConfigurationRevertsIfNotOwner() public { + ZkCoProcessorConfig memory config = ZkCoProcessorConfig({ + verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: mockRiscZeroVerifier + }); + + vm.prank(submitter); + vm.expectRevert(); + verifier.setZkConfiguration(ZkCoProcessorType.RiscZero, config, VERIFIER_PROOF_ID); + } + + // ============ revokeCert Tests ============ + + function testRevokeCert() public { + assertTrue(verifier.trustedIntermediateCerts(INTERMEDIATE_CERT_1)); + verifier.revokeCert(INTERMEDIATE_CERT_1); + assertFalse(verifier.trustedIntermediateCerts(INTERMEDIATE_CERT_1)); + } + + function testRevokeCertRevertsIfNotTrusted() public { + bytes32 unknown = keccak256("unknown-cert"); + vm.expectRevert(abi.encodeWithSelector(NitroEnclaveVerifier.CertificateNotFound.selector, unknown)); + verifier.revokeCert(unknown); + } + + function testRevokeCertRevertsIfNotOwner() public { + vm.prank(submitter); + vm.expectRevert(); + verifier.revokeCert(INTERMEDIATE_CERT_1); + } + + // ============ updateVerifierId Tests ============ + + function testUpdateVerifierId() public { + _setUpRiscZeroConfig(); + + bytes32 newVerifierId = keccak256("new-verifier-id"); + bytes32 newVerifierProofId = keccak256("new-verifier-proof-id"); + verifier.updateVerifierId(ZkCoProcessorType.RiscZero, newVerifierId, newVerifierProofId); + + ZkCoProcessorConfig memory config = verifier.getZkConfig(ZkCoProcessorType.RiscZero); + assertEq(config.verifierId, newVerifierId); + assertTrue(verifier.isVerifierIdSupported(ZkCoProcessorType.RiscZero, newVerifierId)); + assertTrue(verifier.isVerifierIdSupported(ZkCoProcessorType.RiscZero, VERIFIER_ID)); + assertEq(verifier.getVerifierProofId(ZkCoProcessorType.RiscZero, newVerifierId), newVerifierProofId); + } + + function testUpdateVerifierIdRevertsIfZero() public { + _setUpRiscZeroConfig(); + vm.expectRevert(NitroEnclaveVerifier.ZeroProgramId.selector); + verifier.updateVerifierId(ZkCoProcessorType.RiscZero, bytes32(0), bytes32(0)); + } + + function testUpdateVerifierIdRevertsIfSame() public { + _setUpRiscZeroConfig(); + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.ProgramIdAlreadyLatest.selector, ZkCoProcessorType.RiscZero, VERIFIER_ID + ) + ); + verifier.updateVerifierId(ZkCoProcessorType.RiscZero, VERIFIER_ID, VERIFIER_PROOF_ID); + } + + function testUpdateVerifierIdRevertsIfNotOwner() public { + _setUpRiscZeroConfig(); + vm.prank(submitter); + vm.expectRevert(); + verifier.updateVerifierId(ZkCoProcessorType.RiscZero, keccak256("new"), keccak256("proof")); + } + + // ============ updateAggregatorId Tests ============ + + function testUpdateAggregatorId() public { + _setUpRiscZeroConfig(); + + bytes32 newAggregatorId = keccak256("new-aggregator-id"); + verifier.updateAggregatorId(ZkCoProcessorType.RiscZero, newAggregatorId); + + ZkCoProcessorConfig memory config = verifier.getZkConfig(ZkCoProcessorType.RiscZero); + assertEq(config.aggregatorId, newAggregatorId); + assertTrue(verifier.isAggregatorIdSupported(ZkCoProcessorType.RiscZero, newAggregatorId)); + assertTrue(verifier.isAggregatorIdSupported(ZkCoProcessorType.RiscZero, AGGREGATOR_ID)); + } + + function testUpdateAggregatorIdRevertsIfZero() public { + _setUpRiscZeroConfig(); + vm.expectRevert(NitroEnclaveVerifier.ZeroProgramId.selector); + verifier.updateAggregatorId(ZkCoProcessorType.RiscZero, bytes32(0)); + } + + function testUpdateAggregatorIdRevertsIfSame() public { + _setUpRiscZeroConfig(); + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.ProgramIdAlreadyLatest.selector, ZkCoProcessorType.RiscZero, AGGREGATOR_ID + ) + ); + verifier.updateAggregatorId(ZkCoProcessorType.RiscZero, AGGREGATOR_ID); + } + + function testUpdateAggregatorIdRevertsIfNotOwner() public { + _setUpRiscZeroConfig(); + vm.prank(submitter); + vm.expectRevert(); + verifier.updateAggregatorId(ZkCoProcessorType.RiscZero, keccak256("new")); + } + + // ============ removeVerifierId Tests ============ + + function testRemoveVerifierId() public { + _setUpRiscZeroConfig(); + + bytes32 newId = keccak256("new-verifier-id"); + verifier.updateVerifierId(ZkCoProcessorType.RiscZero, newId, keccak256("proof")); + + verifier.removeVerifierId(ZkCoProcessorType.RiscZero, VERIFIER_ID); + assertFalse(verifier.isVerifierIdSupported(ZkCoProcessorType.RiscZero, VERIFIER_ID)); + assertTrue(verifier.isVerifierIdSupported(ZkCoProcessorType.RiscZero, newId)); + } + + function testRemoveVerifierIdRevertsIfLatest() public { + _setUpRiscZeroConfig(); + + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.CannotRemoveLatestProgramId.selector, ZkCoProcessorType.RiscZero, VERIFIER_ID + ) + ); + verifier.removeVerifierId(ZkCoProcessorType.RiscZero, VERIFIER_ID); + } + + function testRemoveVerifierIdRevertsIfNotExists() public { + _setUpRiscZeroConfig(); + bytes32 nonexistent = keccak256("nonexistent"); + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.ProgramIdNotFound.selector, ZkCoProcessorType.RiscZero, nonexistent + ) + ); + verifier.removeVerifierId(ZkCoProcessorType.RiscZero, nonexistent); + } + + function testRemoveVerifierIdRevertsIfNotOwner() public { + _setUpRiscZeroConfig(); + vm.prank(submitter); + vm.expectRevert(); + verifier.removeVerifierId(ZkCoProcessorType.RiscZero, VERIFIER_ID); + } + + // ============ removeAggregatorId Tests ============ + + function testRemoveAggregatorId() public { + _setUpRiscZeroConfig(); + + bytes32 newId = keccak256("new-aggregator-id"); + verifier.updateAggregatorId(ZkCoProcessorType.RiscZero, newId); + + verifier.removeAggregatorId(ZkCoProcessorType.RiscZero, AGGREGATOR_ID); + assertFalse(verifier.isAggregatorIdSupported(ZkCoProcessorType.RiscZero, AGGREGATOR_ID)); + assertTrue(verifier.isAggregatorIdSupported(ZkCoProcessorType.RiscZero, newId)); + } + + function testRemoveAggregatorIdRevertsIfLatest() public { + _setUpRiscZeroConfig(); + + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.CannotRemoveLatestProgramId.selector, ZkCoProcessorType.RiscZero, AGGREGATOR_ID + ) + ); + verifier.removeAggregatorId(ZkCoProcessorType.RiscZero, AGGREGATOR_ID); + } + + function testRemoveAggregatorIdRevertsIfNotExists() public { + _setUpRiscZeroConfig(); + bytes32 nonexistent = keccak256("nonexistent"); + vm.expectRevert( + abi.encodeWithSelector( + NitroEnclaveVerifier.ProgramIdNotFound.selector, ZkCoProcessorType.RiscZero, nonexistent + ) + ); + verifier.removeAggregatorId(ZkCoProcessorType.RiscZero, nonexistent); + } + + function testRemoveAggregatorIdRevertsIfNotOwner() public { + _setUpRiscZeroConfig(); + vm.prank(submitter); + vm.expectRevert(); + verifier.removeAggregatorId(ZkCoProcessorType.RiscZero, AGGREGATOR_ID); + } + + // ============ addVerifyRoute / freezeVerifyRoute Tests ============ + + function testAddVerifyRoute() public { + bytes4 selector = bytes4(keccak256("test")); + address routeVerifier = makeAddr("route-verifier"); + + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, routeVerifier); + assertEq(verifier.getZkVerifier(ZkCoProcessorType.RiscZero, selector), routeVerifier); + } + + function testAddVerifyRouteRevertsIfZeroAddress() public { + vm.expectRevert(NitroEnclaveVerifier.ZeroVerifierAddress.selector); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, bytes4(uint32(0x01)), address(0)); + } + + function testAddVerifyRouteRevertsIfNotOwner() public { + vm.prank(submitter); + vm.expectRevert(); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, bytes4(keccak256("test")), makeAddr("v")); + } + + function testFreezeVerifyRoute() public { + bytes4 selector = bytes4(keccak256("test")); + address routeVerifier = makeAddr("route-verifier"); + + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, routeVerifier); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkRouteFrozen.selector, ZkCoProcessorType.RiscZero, selector) + ); + verifier.getZkVerifier(ZkCoProcessorType.RiscZero, selector); + } + + function testAddVerifyRouteRevertsIfFrozen() public { + bytes4 selector = bytes4(keccak256("test")); + address routeVerifier = makeAddr("route-verifier"); + + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, routeVerifier); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkRouteFrozen.selector, ZkCoProcessorType.RiscZero, selector) + ); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, routeVerifier); + } + + function testFreezeVerifyRouteRevertsIfAlreadyFrozen() public { + bytes4 selector = bytes4(keccak256("test")); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, makeAddr("v")); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkRouteFrozen.selector, ZkCoProcessorType.RiscZero, selector) + ); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + } + + function testFreezeVerifyRouteRevertsIfNotOwner() public { + bytes4 selector = bytes4(keccak256("test")); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, makeAddr("v")); + + vm.prank(submitter); + vm.expectRevert(); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + } + + // ============ getZkVerifier Tests ============ + + function testGetZkVerifierFallsBackToDefault() public { + _setUpRiscZeroConfig(); + + bytes4 unknownSelector = bytes4(0xdeadbeef); + assertEq(verifier.getZkVerifier(ZkCoProcessorType.RiscZero, unknownSelector), mockRiscZeroVerifier); + } + + function testGetZkVerifierReturnsRouteSpecific() public { + _setUpRiscZeroConfig(); + + bytes4 selector = bytes4(keccak256("special")); + address routeVerifier = makeAddr("route-verifier"); + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, routeVerifier); + + assertEq(verifier.getZkVerifier(ZkCoProcessorType.RiscZero, selector), routeVerifier); + } + + // ============ checkTrustedIntermediateCerts Tests ============ + + function testCheckTrustedIntermediateCerts() public view { + bytes32[][] memory reportCerts = new bytes32[][](1); + reportCerts[0] = new bytes32[](3); + reportCerts[0][0] = ROOT_CERT; + reportCerts[0][1] = INTERMEDIATE_CERT_1; + reportCerts[0][2] = INTERMEDIATE_CERT_2; // not trusted + + uint8[] memory results = verifier.checkTrustedIntermediateCerts(reportCerts); + assertEq(results[0], 2); // root + 1 intermediate trusted + } + + function testCheckTrustedIntermediateCertsRevertsIfWrongRoot() public { + bytes32 wrongRoot = keccak256("wrong-root"); + bytes32[][] memory reportCerts = new bytes32[][](1); + reportCerts[0] = new bytes32[](1); + reportCerts[0][0] = wrongRoot; + + vm.expectRevert(abi.encodeWithSelector(NitroEnclaveVerifier.RootCertMismatch.selector, ROOT_CERT, wrongRoot)); + verifier.checkTrustedIntermediateCerts(reportCerts); + } + + // ============ verify — access control ============ + + function testVerifyRevertsIfNotProofSubmitter() public { + vm.expectRevert(NitroEnclaveVerifier.CallerNotProofSubmitter.selector); + verifier.verify("", ZkCoProcessorType.RiscZero, ""); + } + + // ============ verify — ZkVerifierNotConfigured ============ + + function testVerifyRevertsIfZkVerifierNotConfigured() public { + // Set up config WITHOUT a zkVerifier address (zero) + ZkCoProcessorConfig memory config = + ZkCoProcessorConfig({ verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: address(0) }); + verifier.setZkConfiguration(ZkCoProcessorType.RiscZero, config, VERIFIER_PROOF_ID); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + vm.prank(submitter); + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkVerifierNotConfigured.selector, ZkCoProcessorType.RiscZero) + ); + verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + } + + // ============ verify — Unknown_Zk_Coprocessor ============ + + function testVerifyRevertsForUnknownCoprocessor() public { + // Use ZkCoProcessorType.Unknown (0) — not RiscZero or Succinct + ZkCoProcessorConfig memory config = ZkCoProcessorConfig({ + verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: mockRiscZeroVerifier + }); + verifier.setZkConfiguration(ZkCoProcessorType.Unknown, config, VERIFIER_PROOF_ID); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + vm.prank(submitter); + vm.expectRevert(NitroEnclaveVerifier.Unknown_Zk_Coprocessor.selector); + verifier.verify(output, ZkCoProcessorType.Unknown, proofBytes); + } + + // ============ verify — ZkRouteFrozen during verify() ============ + + function testVerifyRevertsIfRouteFrozen() public { + _setUpRiscZeroConfig(); + + bytes4 selector = bytes4(0); // matches the selector in our proofBytes + verifier.addVerifyRoute(ZkCoProcessorType.RiscZero, selector, makeAddr("route-v")); + verifier.freezeVerifyRoute(ZkCoProcessorType.RiscZero, selector); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + vm.prank(submitter); + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkRouteFrozen.selector, ZkCoProcessorType.RiscZero, selector) + ); + verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + } + + // ============ verify — RiscZero happy path ============ + + function testVerifySuccessfulJournal() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.Success)); + } + + function testVerifyJournalRootCertNotTrusted() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + journal.certs[0] = keccak256("wrong-root"); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.RootCertNotTrusted)); + } + + function testVerifyJournalRootCertNotTrustedZeroPrefixLen() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + journal.trustedCertsPrefixLen = 0; + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.RootCertNotTrusted)); + } + + function testVerifyJournalIntermediateCertNotTrusted() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + // Replace trusted intermediate with untrusted one, but keep trustedCertsPrefixLen = 2 + journal.certs[1] = keccak256("untrusted-intermediate"); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.IntermediateCertsNotTrusted)); + } + + function testVerifyJournalInvalidTimestampTooOld() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + // Set timestamp far in the past — more than maxTimeDiff seconds ago (in ms) + journal.timestamp = uint64(block.timestamp - MAX_TIME_DIFF - 1) * 1000; + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.InvalidTimestamp)); + } + + function testVerifyJournalInvalidTimestampFuture() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + // Set timestamp in the future (converted to ms) + journal.timestamp = uint64(block.timestamp + 100) * 1000; + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.InvalidTimestamp)); + } + + function testVerifyCachesNewCerts() public { + _setUpRiscZeroConfig(); + + bytes32 newCert = keccak256("new-leaf-cert"); + assertFalse(verifier.trustedIntermediateCerts(newCert)); + + VerifierJournal memory journal = _createSuccessJournal(); + // Add a new cert beyond the trusted prefix that will get cached + bytes32[] memory certs = new bytes32[](3); + certs[0] = ROOT_CERT; + certs[1] = INTERMEDIATE_CERT_1; + certs[2] = newCert; + journal.certs = certs; + journal.trustedCertsPrefixLen = 2; // only root + 1 intermediate are pre-trusted + + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertTrue(verifier.trustedIntermediateCerts(newCert)); + } + + function testVerifyJournalPassesThroughFailedResult() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + journal.result = VerificationResult.IntermediateCertsNotTrusted; + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.IntermediateCertsNotTrusted)); + } + + // ============ verify — Succinct SP1 happy path ============ + + function testVerifySuccessfulJournalSP1() public { + _setUpSP1Config(); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockSP1Verify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.Succinct, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.Success)); + } + + function testVerifyRevertsIfNotProofSubmitterSP1() public { + vm.expectRevert(NitroEnclaveVerifier.CallerNotProofSubmitter.selector); + verifier.verify("", ZkCoProcessorType.Succinct, ""); + } + + function testVerifyRevertsIfZkVerifierNotConfiguredSP1() public { + ZkCoProcessorConfig memory config = + ZkCoProcessorConfig({ verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: address(0) }); + verifier.setZkConfiguration(ZkCoProcessorType.Succinct, config, VERIFIER_PROOF_ID); + + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + vm.prank(submitter); + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.ZkVerifierNotConfigured.selector, ZkCoProcessorType.Succinct) + ); + verifier.verify(abi.encode(_createSuccessJournal()), ZkCoProcessorType.Succinct, proofBytes); + } + + // ============ batchVerify Tests ============ + + function testBatchVerifyRevertsIfNotProofSubmitter() public { + vm.expectRevert(NitroEnclaveVerifier.CallerNotProofSubmitter.selector); + verifier.batchVerify("", ZkCoProcessorType.RiscZero, ""); + } + + function testBatchVerifySuccess() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + VerifierJournal[] memory outputs = new VerifierJournal[](2); + outputs[0] = journal; + outputs[1] = journal; + + BatchVerifierJournal memory batchJournal = + BatchVerifierJournal({ verifierVk: VERIFIER_PROOF_ID, outputs: outputs }); + + bytes memory output = abi.encode(batchJournal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(AGGREGATOR_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal[] memory results = verifier.batchVerify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(results.length, 2); + assertEq(uint8(results[0].result), uint8(VerificationResult.Success)); + assertEq(uint8(results[1].result), uint8(VerificationResult.Success)); + } + + function testBatchVerifyRevertsIfVerifierVkMismatch() public { + _setUpRiscZeroConfig(); + + bytes32 wrongVk = keccak256("wrong-vk"); + VerifierJournal[] memory outputs = new VerifierJournal[](1); + outputs[0] = _createSuccessJournal(); + + BatchVerifierJournal memory batchJournal = BatchVerifierJournal({ verifierVk: wrongVk, outputs: outputs }); + + bytes memory output = abi.encode(batchJournal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockRiscZeroVerify(AGGREGATOR_ID, output, proofBytes); + + vm.prank(submitter); + vm.expectRevert( + abi.encodeWithSelector(NitroEnclaveVerifier.VerifierVkMismatch.selector, VERIFIER_PROOF_ID, wrongVk) + ); + verifier.batchVerify(output, ZkCoProcessorType.RiscZero, proofBytes); + } + + function testBatchVerifySuccessSP1() public { + _setUpSP1Config(); + + VerifierJournal memory journal = _createSuccessJournal(); + VerifierJournal[] memory outputs = new VerifierJournal[](1); + outputs[0] = journal; + + BatchVerifierJournal memory batchJournal = + BatchVerifierJournal({ verifierVk: VERIFIER_PROOF_ID, outputs: outputs }); + + bytes memory output = abi.encode(batchJournal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + _mockSP1Verify(AGGREGATOR_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal[] memory results = verifier.batchVerify(output, ZkCoProcessorType.Succinct, proofBytes); + + assertEq(results.length, 1); + assertEq(uint8(results[0].result), uint8(VerificationResult.Success)); + } + + // ============ Revoked Cert Invalidates Journal ============ + + function testRevokedCertInvalidatesVerification() public { + _setUpRiscZeroConfig(); + + VerifierJournal memory journal = _createSuccessJournal(); + bytes memory output = abi.encode(journal); + bytes memory proofBytes = abi.encodePacked(bytes4(0), bytes32(0)); + + // Revoke the intermediate cert before verification + verifier.revokeCert(INTERMEDIATE_CERT_1); + + _mockRiscZeroVerify(VERIFIER_ID, output, proofBytes); + + vm.prank(submitter); + VerifierJournal memory result = verifier.verify(output, ZkCoProcessorType.RiscZero, proofBytes); + + assertEq(uint8(result.result), uint8(VerificationResult.IntermediateCertsNotTrusted)); + } + + // ============ Helpers ============ + + function _setUpRiscZeroConfig() internal { + ZkCoProcessorConfig memory config = ZkCoProcessorConfig({ + verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: mockRiscZeroVerifier + }); + verifier.setZkConfiguration(ZkCoProcessorType.RiscZero, config, VERIFIER_PROOF_ID); + } + + function _setUpSP1Config() internal { + ZkCoProcessorConfig memory config = + ZkCoProcessorConfig({ verifierId: VERIFIER_ID, aggregatorId: AGGREGATOR_ID, zkVerifier: mockSP1Verifier }); + verifier.setZkConfiguration(ZkCoProcessorType.Succinct, config, VERIFIER_PROOF_ID); + } + + function _createSuccessJournal() internal view returns (VerifierJournal memory) { + bytes32[] memory certs = new bytes32[](2); + certs[0] = ROOT_CERT; + certs[1] = INTERMEDIATE_CERT_1; + + Pcr[] memory pcrs = new Pcr[](0); + + return VerifierJournal({ + result: VerificationResult.Success, + trustedCertsPrefixLen: 2, + timestamp: uint64(block.timestamp) * 1000, + certs: certs, + userData: "", + nonce: "", + publicKey: "", + pcrs: pcrs, + moduleId: "test-module" + }); + } + + function _mockRiscZeroVerify(bytes32 programId, bytes memory output, bytes memory proofBytes) internal { + // IRiscZeroVerifier.verify(proofBytes, programId, sha256(output)) + vm.mockCall( + mockRiscZeroVerifier, + abi.encodeWithSelector( + bytes4(keccak256("verify(bytes,bytes32,bytes32)")), proofBytes, programId, sha256(output) + ), + "" + ); + } + + function _mockSP1Verify(bytes32 programId, bytes memory output, bytes memory proofBytes) internal { + // ISP1Verifier.verifyProof(programVKey, publicValues, proofBytes) + vm.mockCall( + mockSP1Verifier, + abi.encodeWithSelector( + bytes4(keccak256("verifyProof(bytes32,bytes,bytes)")), programId, output, proofBytes + ), + "" + ); + } +} diff --git a/test/multiproof/Nullify.t.sol b/test/multiproof/Nullify.t.sol index 4674fc381..18ff74f37 100644 --- a/test/multiproof/Nullify.t.sol +++ b/test/multiproof/Nullify.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { ClaimAlreadyResolved } from "src/dispute/lib/Errors.sol"; diff --git a/test/multiproof/TEEProverRegistry.t.sol b/test/multiproof/TEEProverRegistry.t.sol index 5b388f5ff..b2adc64f6 100644 --- a/test/multiproof/TEEProverRegistry.t.sol +++ b/test/multiproof/TEEProverRegistry.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; @@ -6,9 +6,7 @@ import { Test } from "forge-std/Test.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; -import { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { DevTEEProverRegistry } from "src/multiproof/mocks/MockDevTEEProverRegistry.sol"; import { TEEProverRegistry } from "src/multiproof/tee/TEEProverRegistry.sol"; diff --git a/test/multiproof/TEEVerifier.t.sol b/test/multiproof/TEEVerifier.t.sol index 87d6d2669..d92e2304a 100644 --- a/test/multiproof/TEEVerifier.t.sol +++ b/test/multiproof/TEEVerifier.t.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; @@ -6,9 +6,7 @@ import { Test } from "forge-std/Test.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; -import { - INitroEnclaveVerifier -} from "lib/aws-nitro-enclave-attestation/contracts/src/interfaces/INitroEnclaveVerifier.sol"; +import { INitroEnclaveVerifier } from "interfaces/multiproof/tee/INitroEnclaveVerifier.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { MockAnchorStateRegistry } from "scripts/multiproof/mocks/MockAnchorStateRegistry.sol"; From ad8e096c9893f80bc3bc9c5266a0b49401fe0432 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 3 Mar 2026 14:55:09 +0000 Subject: [PATCH 07/18] feat: add FlashblockIndex contract --- src/L2/FlashblockIndex.sol | 45 +++++++++++ test/L2/FlashblockIndex.t.sol | 148 ++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/L2/FlashblockIndex.sol create mode 100644 test/L2/FlashblockIndex.t.sol diff --git a/src/L2/FlashblockIndex.sol b/src/L2/FlashblockIndex.sol new file mode 100644 index 000000000..ab7ce5c28 --- /dev/null +++ b/src/L2/FlashblockIndex.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +/// @title FlashblockIndex +/// @notice Stores the current flashblock index alongside block.number. +/// @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8). +/// Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write. +contract FlashblockIndex { + /// @notice Thrown when the caller is not the authorized builder. + error OnlyBuilder(); + + /// @notice Thrown when calldata is not exactly 1 byte. + error InvalidCalldata(); + + /// @notice The authorized builder address, set at deploy time. + address public immutable BUILDER; + + /// @notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0]. + /// @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks). + uint256 private _packed; + + /// @notice Constructor. + /// @param builder The address authorized to update the flashblock index. + constructor(address builder) { + BUILDER = builder; + } + + /// @notice Sets the flashblock index for the current block. + /// @dev Calldata must be exactly 1 byte representing the flashblock index (uint8). + /// Stores `(block.number << 8) | index` in a single SSTORE. + fallback() external { + if (msg.sender != BUILDER) revert OnlyBuilder(); + if (msg.data.length != 1) revert InvalidCalldata(); + _packed = (uint256(uint48(block.number)) << 8) | uint256(uint8(msg.data[0])); + } + + /// @notice Returns the last stored flashblock index and its associated block number. + /// @return flashblockIndex The flashblock index. + /// @return blockNumber The block number at which the index was set. + function get() external view returns (uint8 flashblockIndex, uint48 blockNumber) { + uint256 packed = _packed; + flashblockIndex = uint8(packed); + blockNumber = uint48(packed >> 8); + } +} diff --git a/test/L2/FlashblockIndex.t.sol b/test/L2/FlashblockIndex.t.sol new file mode 100644 index 000000000..b047328f2 --- /dev/null +++ b/test/L2/FlashblockIndex.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { Test } from "forge-std/Test.sol"; +import { FlashblockIndex } from "src/L2/FlashblockIndex.sol"; + +contract FlashblockIndexTest is Test { + FlashblockIndex flashblockIndex; + address builder; + + function setUp() public { + builder = makeAddr("builder"); + flashblockIndex = new FlashblockIndex(builder); + } + + /// @notice Tests that the constructor correctly sets the BUILDER immutable. + function test_constructor_setsBuilder() external view { + assertEq(flashblockIndex.BUILDER(), builder); + } + + /// @notice Tests that get() returns (0, 0) when no index has ever been written. + function test_get_returnsZeros_whenNeverWritten() external view { + (uint8 index, uint48 blockNumber) = flashblockIndex.get(); + assertEq(index, 0); + assertEq(blockNumber, 0); + } + + /// @notice Tests that get() returns the correct index and block number after a write. + function test_get_returnsCorrectValues(uint8 index, uint48 blockNumber) external { + vm.roll(blockNumber); + (bool success,) = _callFallback({ caller: builder, index: index }); + assertTrue(success); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, index); + assertEq(actualBlock, blockNumber); + } + + /// @notice Tests that the fallback reverts with OnlyBuilder when called by a non-builder address. + function test_fallback_reverts_whenCallerIsNotBuilder(address caller, uint8 index) external { + vm.assume(caller != builder); + (bool success, bytes memory returnData) = _callFallback({ caller: caller, index: index }); + assertFalse(success); + assertEq(bytes4(returnData), FlashblockIndex.OnlyBuilder.selector); + } + + /// @notice Tests that the fallback reverts with InvalidCalldata when called with zero bytes. + function test_fallback_reverts_whenCalldataIsEmpty() external { + vm.prank(builder); + (bool success, bytes memory returnData) = address(flashblockIndex).call(""); + assertFalse(success); + assertEq(bytes4(returnData), FlashblockIndex.InvalidCalldata.selector); + } + + /// @notice Tests that the fallback reverts with InvalidCalldata when called with more than 1 byte. + function test_fallback_reverts_whenCalldataIsTooLong(uint8 extra) external { + vm.prank(builder); + (bool success, bytes memory returnData) = address(flashblockIndex).call(abi.encodePacked(uint8(1), extra)); + assertFalse(success); + assertEq(bytes4(returnData), FlashblockIndex.InvalidCalldata.selector); + } + + /// @notice Tests that the fallback stores the index and block number correctly when called by the builder. + function test_fallback_setsIndex(uint8 index, uint48 blockNumber) external { + vm.roll(blockNumber); + (bool success,) = _callFallback({ caller: builder, index: index }); + assertTrue(success); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, index); + assertEq(actualBlock, blockNumber); + } + + /// @notice Tests that a second fallback call overwrites the previous value at a different block. + function test_fallback_overwritesPreviousValue() external { + uint48 firstBlock = 100; + uint8 firstIndex = 5; + vm.roll(firstBlock); + (bool s1,) = _callFallback({ caller: builder, index: firstIndex }); + assertTrue(s1); + + uint48 secondBlock = 200; + uint8 secondIndex = 10; + vm.roll(secondBlock); + (bool s2,) = _callFallback({ caller: builder, index: secondIndex }); + assertTrue(s2); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, secondIndex); + assertEq(actualBlock, secondBlock); + } + + /// @notice Tests that a second fallback call overwrites the previous value within the same block. + function test_fallback_overwritesWithinSameBlock() external { + uint48 blockNumber = 100; + uint8 firstIndex = 5; + uint8 secondIndex = 10; + + vm.roll(blockNumber); + (bool s1,) = _callFallback({ caller: builder, index: firstIndex }); + assertTrue(s1); + + (bool s2,) = _callFallback({ caller: builder, index: secondIndex }); + assertTrue(s2); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, secondIndex); + assertEq(actualBlock, blockNumber); + } + + /// @notice Tests that the fallback correctly stores the maximum uint48 block number. + function test_fallback_storesMaxBlockNumber() external { + uint48 maxBlock = type(uint48).max; + uint8 index = 1; + + vm.roll(maxBlock); + (bool success,) = _callFallback({ caller: builder, index: index }); + assertTrue(success); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, index); + assertEq(actualBlock, maxBlock); + } + + /// @notice Tests that the block number is truncated to uint48 when it exceeds the max value. + function test_fallback_truncatesBlockNumber() external { + uint256 overflowBlock = uint256(type(uint48).max) + 1; + uint8 index = 1; + + vm.roll(overflowBlock); + (bool success,) = _callFallback({ caller: builder, index: index }); + assertTrue(success); + + (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); + assertEq(actualIndex, index); + assertEq(actualBlock, 0); + } + + /// @notice Helper function to call the fallback with the given caller and index. + /// @param caller The address of the caller. + /// @param index The index to call the fallback with. + /// @return success True if the fallback call succeeded. + /// @return returnData The return data from the fallback call. + function _callFallback(address caller, uint8 index) private returns (bool success, bytes memory returnData) { + vm.prank(caller); + (success, returnData) = address(flashblockIndex).call(abi.encodePacked(index)); + } +} From ca8553cf722274ffa2f9ea693391ffe0be2339a9 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 3 Mar 2026 16:14:36 +0000 Subject: [PATCH 08/18] refactor: make FlashblockIndex upgradeable and emit FlashblockIndexUpdated event --- src/L2/FlashblockIndex.sol | 20 +++++++++++++++++++- test/L2/FlashblockIndex.t.sol | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/L2/FlashblockIndex.sol b/src/L2/FlashblockIndex.sol index ab7ce5c28..eccc5a0c2 100644 --- a/src/L2/FlashblockIndex.sol +++ b/src/L2/FlashblockIndex.sol @@ -1,17 +1,30 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; + +/// @custom:upgradeable /// @title FlashblockIndex /// @notice Stores the current flashblock index alongside block.number. /// @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8). /// Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write. -contract FlashblockIndex { +contract FlashblockIndex is Initializable, ISemver { /// @notice Thrown when the caller is not the authorized builder. error OnlyBuilder(); /// @notice Thrown when calldata is not exactly 1 byte. error InvalidCalldata(); + /// @notice Emitted when the flashblock index is updated. + /// @param flashblockIndex The new flashblock index. + /// @param blockNumber The block number at which the index was set. + event FlashblockIndexUpdated(uint8 indexed flashblockIndex, uint48 indexed blockNumber); + + /// @notice Semantic version. + /// @custom:semver 1.0.0 + string public constant override version = "1.0.0"; + /// @notice The authorized builder address, set at deploy time. address public immutable BUILDER; @@ -23,8 +36,12 @@ contract FlashblockIndex { /// @param builder The address authorized to update the flashblock index. constructor(address builder) { BUILDER = builder; + _disableInitializers(); } + /// @notice Initializer. + function initialize() external initializer { } + /// @notice Sets the flashblock index for the current block. /// @dev Calldata must be exactly 1 byte representing the flashblock index (uint8). /// Stores `(block.number << 8) | index` in a single SSTORE. @@ -32,6 +49,7 @@ contract FlashblockIndex { if (msg.sender != BUILDER) revert OnlyBuilder(); if (msg.data.length != 1) revert InvalidCalldata(); _packed = (uint256(uint48(block.number)) << 8) | uint256(uint8(msg.data[0])); + emit FlashblockIndexUpdated(uint8(msg.data[0]), uint48(block.number)); } /// @notice Returns the last stored flashblock index and its associated block number. diff --git a/test/L2/FlashblockIndex.t.sol b/test/L2/FlashblockIndex.t.sol index b047328f2..1739a49ac 100644 --- a/test/L2/FlashblockIndex.t.sol +++ b/test/L2/FlashblockIndex.t.sol @@ -5,6 +5,8 @@ import { Test } from "forge-std/Test.sol"; import { FlashblockIndex } from "src/L2/FlashblockIndex.sol"; contract FlashblockIndexTest is Test { + event FlashblockIndexUpdated(uint8 indexed flashblockIndex, uint48 indexed blockNumber); + FlashblockIndex flashblockIndex; address builder; @@ -18,6 +20,17 @@ contract FlashblockIndexTest is Test { assertEq(flashblockIndex.BUILDER(), builder); } + /// @notice Tests that initialize() reverts on the implementation contract since initializers are disabled. + function test_initialize_reverts_whenCalledOnImplementation() external { + vm.expectRevert("Initializable: contract is already initialized"); + flashblockIndex.initialize(); + } + + /// @notice Tests that version() returns "1.0.0". + function test_version_returnsCorrectValue() external view { + assertEq(flashblockIndex.version(), "1.0.0"); + } + /// @notice Tests that get() returns (0, 0) when no index has ever been written. function test_get_returnsZeros_whenNeverWritten() external view { (uint8 index, uint48 blockNumber) = flashblockIndex.get(); @@ -71,6 +84,15 @@ contract FlashblockIndexTest is Test { assertEq(actualBlock, blockNumber); } + /// @notice Tests that the fallback emits FlashblockIndexUpdated with the correct parameters. + function test_fallback_emitsFlashblockIndexUpdated(uint8 index, uint48 blockNumber) external { + vm.roll(blockNumber); + vm.expectEmit(address(flashblockIndex)); + emit FlashblockIndexUpdated(index, blockNumber); + (bool success,) = _callFallback({ caller: builder, index: index }); + assertTrue(success); + } + /// @notice Tests that a second fallback call overwrites the previous value at a different block. function test_fallback_overwritesPreviousValue() external { uint48 firstBlock = 100; @@ -136,6 +158,8 @@ contract FlashblockIndexTest is Test { assertEq(actualBlock, 0); } + // --- Helper --- + /// @notice Helper function to call the fallback with the given caller and index. /// @param caller The address of the caller. /// @param index The index to call the fallback with. From a0a7b8c6aa40633b0ecc7be114134b7049af5526 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 3 Mar 2026 15:37:01 +0000 Subject: [PATCH 09/18] feat: setup rust bindings crate --- .gitignore | 2 + crates/bindings/Cargo.lock | 3621 +++++++++++++++++ crates/bindings/Cargo.toml | 8 + .../bindings/artifacts/FlashblockIndex.json | 1 + crates/bindings/src/l2/flashblock_index.rs | 10 + crates/bindings/src/l2/mod.rs | 2 + crates/bindings/src/lib.rs | 1 + 7 files changed, 3645 insertions(+) create mode 100644 crates/bindings/Cargo.lock create mode 100644 crates/bindings/Cargo.toml create mode 100644 crates/bindings/artifacts/FlashblockIndex.json create mode 100644 crates/bindings/src/l2/flashblock_index.rs create mode 100644 crates/bindings/src/l2/mod.rs create mode 100644 crates/bindings/src/lib.rs diff --git a/.gitignore b/.gitignore index afbd7e903..b3a454e61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Artifacts and Cache artifacts +!crates/bindings/artifacts/ forge-artifacts +target cache broadcast kout-proofs diff --git a/crates/bindings/Cargo.lock b/crates/bindings/Cargo.lock new file mode 100644 index 000000000..8cd1ba9b5 --- /dev/null +++ b/crates/bindings/Cargo.lock @@ -0,0 +1,3621 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy-chains" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-trie", + "alloy-tx-macros", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-consensus-any" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca63b7125a981415898ffe2a2a696c83696c9c6bdb1671c8a912946bbd8e49e7" +dependencies = [ + "alloy-consensus", + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-dyn-abi" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2db5c583aaef0255aa63a4fe827f826090142528bba48d1bf4119b62780cad" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2124" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "crc", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip2930" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", + "thiserror", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8222b1d88f9a6d03be84b0f5e76bb60cd83991b43ad8ab6477f0e4a7809b98d" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8" +dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", + "alloy-eip7928", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "borsh", + "c-kzg", + "derive_more", + "either", + "serde", + "serde_with", + "sha2", + "thiserror", +] + +[[package]] +name = "alloy-json-abi" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff42cd777eea61f370c0b10f2648a1c81e0b783066cd7269228aa993afd487f7" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "http", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cbca04f9b410fdc51aaaf88433cbac761213905a65fe832058bcf6690585762" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-any", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "derive_more", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "foldhash 0.2.0", + "hashbrown 0.16.1", + "indexmap 2.13.0", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand 0.9.2", + "rapidhash", + "ruint", + "rustc-hash", + "serde", + "sha3", +] + +[[package]] +name = "alloy-provider" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d181c8cc7cf4805d7e589bf4074d56d55064fa1a979f005a45a62b047616d870" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-signer", + "alloy-sol-types", + "alloy-transport", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "either", + "futures", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "wasmtimer", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e93e50f64a77ad9c5470bf2ad0ca02f228da70c792a8f06634801e202579f35e" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-rpc-client" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2792758a93ae32a32e9047c843d536e1448044f78422d71bf7d7c05149e103f" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "futures", + "pin-project", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types-any" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd720b63f82b457610f2eaaf1f32edf44efffe03ae25d537632e7d23e7929e1a" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9" +dependencies = [ + "alloy-consensus", + "alloy-consensus-any", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "serde_with", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2425c6f314522c78e8198979c8cbf6769362be4da381d4152ea8eefce383535d" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "either", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.13.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "sha3", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.117", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64612d29379782a5dde6f4b6570d9c756d734d760c0c94c254d361e678a6591f" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa186e560d523d196580c48bf00f1bf62e63041f28ecf276acc22f8b27bb9f53" +dependencies = [ + "alloy-json-rpc", + "auto_impl", + "base64", + "derive_more", + "futures", + "futures-utils-wasm", + "parking_lot", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-trie" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d7fd448ab0a017de542de1dcca7a58e7019fe0e7a34ed3f9543ebddf6aceffa" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more", + "nybbles", + "serde", + "smallvec", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "auto_impl" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base-contracts-bindings" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-sol-types", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitcoin-io" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f582957c24870b7bfd12bf562c40b4734b533cafbaf8ded31d6d85f462c01" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "const-hex" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" +dependencies = [ + "cfg-if", + "cpufeatures", + "proptest", + "serde_core", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "nybbles" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +dependencies = [ + "alloy-rlp", + "cfg-if", + "proptest", + "ruint", + "serde", + "smallvec", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.2", + "rlp", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.27", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" +dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b31139435f327c93c6038ed350ae4588e2c70a13d50599509fee6349967ba35a" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/crates/bindings/Cargo.toml b/crates/bindings/Cargo.toml new file mode 100644 index 000000000..5de725986 --- /dev/null +++ b/crates/bindings/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "base-contracts-bindings" +version = "0.1.0" +edition = "2021" + +[dependencies] +alloy-contract = "1.5.0" +alloy-sol-types = { version = "1.5.0", features = ["json"] } diff --git a/crates/bindings/artifacts/FlashblockIndex.json b/crates/bindings/artifacts/FlashblockIndex.json new file mode 100644 index 000000000..ec080ccb2 --- /dev/null +++ b/crates/bindings/artifacts/FlashblockIndex.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"builder","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"BUILDER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"get","inputs":[],"outputs":[{"name":"flashblockIndex","type":"uint8","internalType":"uint8"},{"name":"blockNumber","type":"uint48","internalType":"uint48"}],"stateMutability":"view"},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"OnlyBuilder","inputs":[]}],"bytecode":{"object":"0x60a060405234801561001057600080fd5b5060405161025538038061025583398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516101c461009160003960008181604e015261014101526101c46000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461010f578063ecfd1b631461013c575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100a5576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100df576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660008181106100f3576100f3610188565b9091013560f81c4360081b66ffffffffffff0016176000819055005b600054600881901c6040805160ff909316835265ffffffffffff9091166020830152015b60405180910390f35b6101637f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a","sourceMap":"343:1626:19:-:0;;;1016:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1055:17:19;;;343:1626;;14:290:21;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:21;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:21:o;:::-;343:1626:19;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461010f578063ecfd1b631461013c575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100a5576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100df576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660008181106100f3576100f3610188565b9091013560f81c4360081b66ffffffffffff0016176000819055005b600054600881901c6040805160ff909316835265ffffffffffff9091166020830152015b60405180910390f35b6101637f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a","sourceMap":"343:1626:19:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1342:10;:21;1356:7;1342:21;;1338:47;;1372:13;;;;;;;;;;;;;;1338:47;1418:1;1399:8;:20;1395:50;;1428:17;;;;;;;;;;;;;;1395:50;1518:8;;1527:1;1518:11;;;;;;;:::i;:::-;;;;;;;1481:12;1499:1;1466:34;;;1465:66;1455:7;:76;;;1465:66;1761:206;1799:21;1869:7;1958:1;1948:11;;;1761:206;;;401:4:21;389:17;;;371:36;;455:14;443:27;;;438:2;423:18;;416:55;344:18;1761:206:19;;;;;;;;628:32;;;;;;;;658:42:21;646:55;;;628:74;;616:2;601:18;628:32:19;482:226:21;14:184;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15","linkReferences":{},"immutableReferences":{"39139":[{"start":78,"length":32},{"start":321,"length":32}]}},"methodIdentifiers":{"BUILDER()":"ecfd1b63","get()":"6d4ce63c"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyBuilder\",\"type\":\"error\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"BUILDER\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"builder\":\"The address authorized to update the flashblock index.\"}},\"get()\":{\"returns\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The flashblock index.\"}}},\"stateVariables\":{\"_packed\":{\"details\":\"Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks).\"}},\"title\":\"FlashblockIndex\",\"version\":1},\"userdoc\":{\"errors\":{\"InvalidCalldata()\":[{\"notice\":\"Thrown when calldata is not exactly 1 byte.\"}],\"OnlyBuilder()\":[{\"notice\":\"Thrown when the caller is not the authorized builder.\"}]},\"kind\":\"user\",\"methods\":{\"BUILDER()\":{\"notice\":\"The authorized builder address, set at deploy time.\"},\"constructor\":{\"notice\":\"Constructor.\"},\"get()\":{\"notice\":\"Returns the last stored flashblock index and its associated block number.\"}},\"notice\":\"Stores the current flashblock index alongside block.number.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/L2/FlashblockIndex.sol\":\"FlashblockIndex\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[\":@lib-keccak/=lib/lib-keccak/contracts/lib/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@rari-capital/solmate/=lib/solmate/\",\":@solady-test/=lib/lib-keccak/lib/solady/test/\",\":@solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":@solady/=lib/solady/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":interfaces/=interfaces/\",\":kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/\",\":lib-keccak/=lib/lib-keccak/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":safe-contracts/=lib/safe-contracts/contracts/\",\":solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":solady/=lib/solady/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"src/L2/FlashblockIndex.sol\":{\"keccak256\":\"0x964b79b3878d9c129e5cc81592fe852eb93b87d95283db238ddabd51b93e503f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ed8f0749b8052af49738678cf33a3d9c97ab27e42d1e56681ba5b2c2d804df8\",\"dweb:/ipfs/QmUUx66BhAv5YDWxEM9pPyRqTx8r2sE7ddkKT8TJ1SAixk\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"builder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"InvalidCalldata"},{"inputs":[],"type":"error","name":"OnlyBuilder"},{"inputs":[],"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"stateMutability":"view","type":"function","name":"BUILDER","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"get","outputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8"},{"internalType":"uint48","name":"blockNumber","type":"uint48"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"version":1},"userdoc":{"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."}},"version":1}},"settings":{"remappings":["@lib-keccak/=lib/lib-keccak/contracts/lib/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@rari-capital/solmate/=lib/solmate/","@solady-test/=lib/lib-keccak/lib/solady/test/","@solady-v0.0.245/=lib/solady-v0.0.245/src/","@solady/=lib/solady/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","interfaces/=interfaces/","kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/","lib-keccak/=lib/lib-keccak/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/","openzeppelin-contracts/=lib/openzeppelin-contracts/","safe-contracts/=lib/safe-contracts/contracts/","solady-v0.0.245/=lib/solady-v0.0.245/src/","solady/=lib/solady/","solmate/=lib/solmate/src/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/L2/FlashblockIndex.sol":"FlashblockIndex"},"evmVersion":"london","libraries":{}},"sources":{"src/L2/FlashblockIndex.sol":{"keccak256":"0x964b79b3878d9c129e5cc81592fe852eb93b87d95283db238ddabd51b93e503f","urls":["bzz-raw://0ed8f0749b8052af49738678cf33a3d9c97ab27e42d1e56681ba5b2c2d804df8","dweb:/ipfs/QmUUx66BhAv5YDWxEM9pPyRqTx8r2sE7ddkKT8TJ1SAixk"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":39142,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_packed","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."}},"errors":{"InvalidCalldata()":[{"notice":"Thrown when calldata is not exactly 1 byte."}],"OnlyBuilder()":[{"notice":"Thrown when the caller is not the authorized builder."}]},"notice":"Stores the current flashblock index alongside block.number."},"devdoc":{"version":1,"kind":"dev","details":"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"title":"FlashblockIndex"},"ast":{"absolutePath":"src/L2/FlashblockIndex.sol","id":39231,"exportedSymbols":{"FlashblockIndex":[39230]},"nodeType":"SourceUnit","src":"32:1938:19","nodes":[{"id":39129,"nodeType":"PragmaDirective","src":"32:23:19","nodes":[],"literals":["solidity","0.8",".15"]},{"id":39230,"nodeType":"ContractDefinition","src":"343:1626:19","nodes":[{"id":39133,"nodeType":"ErrorDefinition","src":"444:20:19","nodes":[],"documentation":{"id":39131,"nodeType":"StructuredDocumentation","src":"374:65:19","text":"@notice Thrown when the caller is not the authorized builder."},"errorSelector":"357a555d","name":"OnlyBuilder","nameLocation":"450:11:19","parameters":{"id":39132,"nodeType":"ParameterList","parameters":[],"src":"461:2:19"}},{"id":39136,"nodeType":"ErrorDefinition","src":"530:24:19","nodes":[],"documentation":{"id":39134,"nodeType":"StructuredDocumentation","src":"470:55:19","text":"@notice Thrown when calldata is not exactly 1 byte."},"errorSelector":"8129bbcd","name":"InvalidCalldata","nameLocation":"536:15:19","parameters":{"id":39135,"nodeType":"ParameterList","parameters":[],"src":"551:2:19"}},{"id":39139,"nodeType":"VariableDeclaration","src":"628:32:19","nodes":[],"constant":false,"documentation":{"id":39137,"nodeType":"StructuredDocumentation","src":"560:63:19","text":"@notice The authorized builder address, set at deploy time."},"functionSelector":"ecfd1b63","mutability":"immutable","name":"BUILDER","nameLocation":"653:7:19","scope":39230,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39138,"name":"address","nodeType":"ElementaryTypeName","src":"628:7:19","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"public"},{"id":39142,"nodeType":"VariableDeclaration","src":"879:23:19","nodes":[],"constant":false,"documentation":{"id":39140,"nodeType":"StructuredDocumentation","src":"667:207:19","text":"@notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0].\n @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks)."},"mutability":"mutable","name":"_packed","nameLocation":"895:7:19","scope":39230,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39141,"name":"uint256","nodeType":"ElementaryTypeName","src":"879:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"private"},{"id":39153,"nodeType":"FunctionDefinition","src":"1016:63:19","nodes":[],"body":{"id":39152,"nodeType":"Block","src":"1045:34:19","nodes":[],"statements":[{"expression":{"id":39150,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39148,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39139,"src":"1055:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":39149,"name":"builder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39145,"src":"1065:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1055:17:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":39151,"nodeType":"ExpressionStatement","src":"1055:17:19"}]},"documentation":{"id":39143,"nodeType":"StructuredDocumentation","src":"909:102:19","text":"@notice Constructor.\n @param builder The address authorized to update the flashblock index."},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39146,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39145,"mutability":"mutable","name":"builder","nameLocation":"1036:7:19","nodeType":"VariableDeclaration","scope":39153,"src":"1028:15:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39144,"name":"address","nodeType":"ElementaryTypeName","src":"1028:7:19","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1027:17:19"},"returnParameters":{"id":39147,"nodeType":"ParameterList","parameters":[],"src":"1045:0:19"},"scope":39230,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":39200,"nodeType":"FunctionDefinition","src":"1308:230:19","nodes":[],"body":{"id":39199,"nodeType":"Block","src":"1328:210:19","nodes":[],"statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":39160,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":39157,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1342:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39158,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"1342:10:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":39159,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39139,"src":"1356:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1342:21:19","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39164,"nodeType":"IfStatement","src":"1338:47:19","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39161,"name":"OnlyBuilder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39133,"src":"1372:11:19","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1372:13:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39163,"nodeType":"RevertStatement","src":"1365:20:19"}},{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39169,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"expression":{"id":39165,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1399:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39166,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"1399:8:19","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39167,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1399:15:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"hexValue":"31","id":39168,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1418:1:19","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"1399:20:19","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39173,"nodeType":"IfStatement","src":"1395:50:19","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39170,"name":"InvalidCalldata","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39136,"src":"1428:15:19","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39171,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1428:17:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39172,"nodeType":"RevertStatement","src":"1421:24:19"}},{"expression":{"id":39197,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39174,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39142,"src":"1455:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39196,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"components":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39184,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"expression":{"id":39179,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"1481:5:19","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39180,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"1481:12:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39178,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1474:6:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39177,"name":"uint48","nodeType":"ElementaryTypeName","src":"1474:6:19","typeDescriptions":{}}},"id":39181,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1474:20:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39176,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1466:7:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39175,"name":"uint256","nodeType":"ElementaryTypeName","src":"1466:7:19","typeDescriptions":{}}},"id":39182,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1466:29:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<<","rightExpression":{"hexValue":"38","id":39183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1499:1:19","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"1466:34:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"id":39185,"isConstant":false,"isInlineArray":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"TupleExpression","src":"1465:36:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"|","rightExpression":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39190,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1518:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39191,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"1518:8:19","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39193,"indexExpression":{"hexValue":"30","id":39192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1527:1:19","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"1518:11:19","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39189,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1512:5:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39188,"name":"uint8","nodeType":"ElementaryTypeName","src":"1512:5:19","typeDescriptions":{}}},"id":39194,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1512:18:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"}],"id":39187,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1504:7:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39186,"name":"uint256","nodeType":"ElementaryTypeName","src":"1504:7:19","typeDescriptions":{}}},"id":39195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1504:27:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"1465:66:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"1455:76:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":39198,"nodeType":"ExpressionStatement","src":"1455:76:19"}]},"documentation":{"id":39154,"nodeType":"StructuredDocumentation","src":"1085:218:19","text":"@notice Sets the flashblock index for the current block.\n @dev Calldata must be exactly 1 byte representing the flashblock index (uint8).\n Stores `(block.number << 8) | index` in a single SSTORE."},"implemented":true,"kind":"fallback","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39155,"nodeType":"ParameterList","parameters":[],"src":"1316:2:19"},"returnParameters":{"id":39156,"nodeType":"ParameterList","parameters":[],"src":"1328:0:19"},"scope":39230,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39229,"nodeType":"FunctionDefinition","src":"1761:206:19","nodes":[],"body":{"id":39228,"nodeType":"Block","src":"1842:125:19","nodes":[],"statements":[{"assignments":[39209],"declarations":[{"constant":false,"id":39209,"mutability":"mutable","name":"packed","nameLocation":"1860:6:19","nodeType":"VariableDeclaration","scope":39228,"src":"1852:14:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39208,"name":"uint256","nodeType":"ElementaryTypeName","src":"1852:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39211,"initialValue":{"id":39210,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39142,"src":"1869:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1852:24:19"},{"expression":{"id":39217,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39212,"name":"flashblockIndex","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39204,"src":"1886:15:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":39215,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39209,"src":"1910:6:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39214,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1904:5:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39213,"name":"uint8","nodeType":"ElementaryTypeName","src":"1904:5:19","typeDescriptions":{}}},"id":39216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1904:13:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"src":"1886:31:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"id":39218,"nodeType":"ExpressionStatement","src":"1886:31:19"},{"expression":{"id":39226,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39219,"name":"blockNumber","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39206,"src":"1927:11:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39224,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":39222,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39209,"src":"1948:6:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">>","rightExpression":{"hexValue":"38","id":39223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1958:1:19","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"1948:11:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39221,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1941:6:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39220,"name":"uint48","nodeType":"ElementaryTypeName","src":"1941:6:19","typeDescriptions":{}}},"id":39225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1941:19:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"src":"1927:33:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"id":39227,"nodeType":"ExpressionStatement","src":"1927:33:19"}]},"documentation":{"id":39201,"nodeType":"StructuredDocumentation","src":"1544:212:19","text":"@notice Returns the last stored flashblock index and its associated block number.\n @return flashblockIndex The flashblock index.\n @return blockNumber The block number at which the index was set."},"functionSelector":"6d4ce63c","implemented":true,"kind":"function","modifiers":[],"name":"get","nameLocation":"1770:3:19","parameters":{"id":39202,"nodeType":"ParameterList","parameters":[],"src":"1773:2:19"},"returnParameters":{"id":39207,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39204,"mutability":"mutable","name":"flashblockIndex","nameLocation":"1805:15:19","nodeType":"VariableDeclaration","scope":39229,"src":"1799:21:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39203,"name":"uint8","nodeType":"ElementaryTypeName","src":"1799:5:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39206,"mutability":"mutable","name":"blockNumber","nameLocation":"1829:11:19","nodeType":"VariableDeclaration","scope":39229,"src":"1822:18:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39205,"name":"uint48","nodeType":"ElementaryTypeName","src":"1822:6:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"1798:43:19"},"scope":39230,"stateMutability":"view","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"FlashblockIndex","contractDependencies":[],"contractKind":"contract","documentation":{"id":39130,"nodeType":"StructuredDocumentation","src":"57:286:19","text":"@title FlashblockIndex\n @notice Stores the current flashblock index alongside block.number.\n @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8).\n Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write."},"fullyImplemented":true,"linearizedBaseContracts":[39230],"name":"FlashblockIndex","nameLocation":"352:15:19","scope":39231,"usedErrors":[39133,39136]}],"license":"MIT"},"id":19} \ No newline at end of file diff --git a/crates/bindings/src/l2/flashblock_index.rs b/crates/bindings/src/l2/flashblock_index.rs new file mode 100644 index 000000000..6976d89df --- /dev/null +++ b/crates/bindings/src/l2/flashblock_index.rs @@ -0,0 +1,10 @@ +use alloy_sol_types::sol; + +sol!( + #[sol(rpc, abi)] + FlashblockIndex, + concat!( + env!("CARGO_MANIFEST_DIR"), + "/artifacts/FlashblockIndex.json" + ) +); diff --git a/crates/bindings/src/l2/mod.rs b/crates/bindings/src/l2/mod.rs new file mode 100644 index 000000000..15a59fd87 --- /dev/null +++ b/crates/bindings/src/l2/mod.rs @@ -0,0 +1,2 @@ +mod flashblock_index; +pub use flashblock_index::FlashblockIndex; diff --git a/crates/bindings/src/lib.rs b/crates/bindings/src/lib.rs new file mode 100644 index 000000000..a9f32026d --- /dev/null +++ b/crates/bindings/src/lib.rs @@ -0,0 +1 @@ +pub mod l2; From 9d223e5f44f870242284791f557a3a0795f546d7 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Wed, 4 Mar 2026 08:54:56 +0000 Subject: [PATCH 10/18] refactor: move bindings into bindings/go and bindings/rust --- .gitignore | 2 +- bindings/{ => go}/balance_tracker.go | 0 bindings/{ => go}/fee_disburser.go | 0 bindings/{ => go}/go.mod | 2 +- bindings/{ => go}/go.sum | 0 {crates/bindings => bindings/rust}/Cargo.lock | 0 {crates/bindings => bindings/rust}/Cargo.toml | 0 bindings/rust/artifacts/FlashblockIndex.json | 1 + {crates/bindings => bindings/rust}/src/l2/flashblock_index.rs | 0 {crates/bindings => bindings/rust}/src/l2/mod.rs | 0 {crates/bindings => bindings/rust}/src/lib.rs | 0 crates/bindings/artifacts/FlashblockIndex.json | 1 - 12 files changed, 3 insertions(+), 3 deletions(-) rename bindings/{ => go}/balance_tracker.go (100%) rename bindings/{ => go}/fee_disburser.go (100%) rename bindings/{ => go}/go.mod (96%) rename bindings/{ => go}/go.sum (100%) rename {crates/bindings => bindings/rust}/Cargo.lock (100%) rename {crates/bindings => bindings/rust}/Cargo.toml (100%) create mode 100644 bindings/rust/artifacts/FlashblockIndex.json rename {crates/bindings => bindings/rust}/src/l2/flashblock_index.rs (100%) rename {crates/bindings => bindings/rust}/src/l2/mod.rs (100%) rename {crates/bindings => bindings/rust}/src/lib.rs (100%) delete mode 100644 crates/bindings/artifacts/FlashblockIndex.json diff --git a/.gitignore b/.gitignore index b3a454e61..2d2ee8362 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Artifacts and Cache artifacts -!crates/bindings/artifacts/ +!bindings/rust/artifacts/ forge-artifacts target cache diff --git a/bindings/balance_tracker.go b/bindings/go/balance_tracker.go similarity index 100% rename from bindings/balance_tracker.go rename to bindings/go/balance_tracker.go diff --git a/bindings/fee_disburser.go b/bindings/go/fee_disburser.go similarity index 100% rename from bindings/fee_disburser.go rename to bindings/go/fee_disburser.go diff --git a/bindings/go.mod b/bindings/go/go.mod similarity index 96% rename from bindings/go.mod rename to bindings/go/go.mod index 96c1023e9..96acf234e 100644 --- a/bindings/go.mod +++ b/bindings/go/go.mod @@ -1,4 +1,4 @@ -module github.com/base/contracts/bindings +module github.com/base/contracts/bindings/go go 1.23.0 diff --git a/bindings/go.sum b/bindings/go/go.sum similarity index 100% rename from bindings/go.sum rename to bindings/go/go.sum diff --git a/crates/bindings/Cargo.lock b/bindings/rust/Cargo.lock similarity index 100% rename from crates/bindings/Cargo.lock rename to bindings/rust/Cargo.lock diff --git a/crates/bindings/Cargo.toml b/bindings/rust/Cargo.toml similarity index 100% rename from crates/bindings/Cargo.toml rename to bindings/rust/Cargo.toml diff --git a/bindings/rust/artifacts/FlashblockIndex.json b/bindings/rust/artifacts/FlashblockIndex.json new file mode 100644 index 000000000..1e5e73e13 --- /dev/null +++ b/bindings/rust/artifacts/FlashblockIndex.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[{"name":"builder","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"BUILDER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"get","inputs":[],"outputs":[{"name":"flashblockIndex","type":"uint8","internalType":"uint8"},{"name":"blockNumber","type":"uint48","internalType":"uint48"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"version","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"event","name":"FlashblockIndexUpdated","inputs":[{"name":"flashblockIndex","type":"uint8","indexed":true,"internalType":"uint8"},{"name":"blockNumber","type":"uint48","indexed":true,"internalType":"uint48"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint8","indexed":false,"internalType":"uint8"}],"anonymous":false},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"OnlyBuilder","inputs":[]}],"bytecode":{"object":"0x60a060405234801561001057600080fd5b506040516105dc3803806105dc83398101604081905261002f9161010a565b6001600160a01b03811660805261004461004a565b5061013a565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015610108576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011c57600080fd5b81516001600160a01b038116811461013357600080fd5b9392505050565b60805161048161015b60003960008181606401526101fd01526104816000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a","sourceMap":"515:2248:22:-:0;;;1618:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1657:17:22;;;;1684:22;:20;:22::i;:::-;1618:95;515:2248;;5366:279:20;5434:13;;;;;;;5433:14;5425:66;;;;-1:-1:-1;;;5425:66:20;;511:2:24;5425:66:20;;;493:21:24;550:2;530:18;;;523:30;589:34;569:18;;;562:62;-1:-1:-1;;;640:18:24;;;633:37;687:19;;5425:66:20;;;;;;;;5505:12;;5520:15;5505:12;;;:30;5501:138;;;5551:12;:30;;-1:-1:-1;;5551:30:20;5566:15;5551:30;;;;;;5600:28;;859:36:24;;;5600:28:20;;847:2:24;832:18;5600:28:20;;;;;;;5501:138;5366:279::o;14:290:24:-;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:24;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:24:o;717:184::-;515:2248:22;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a","sourceMap":"515:2248:22:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2057:10;:21;2071:7;2057:21;;2053:47;;2087:13;;;;;;;;;;;;;;2053:47;2133:1;2114:8;:20;2110:50;;2143:17;;;;;;;;;;;;;;2110:50;2233:8;;2242:1;2233:11;;;;;;;:::i;:::-;;;;;;;2196:12;2214:1;2181:34;;;;;2180:66;;;;2170:7;:76;2181:29;;;-1:-1:-1;2290:8:22;;;;:11;;;;:::i;:::-;2261:64;;2290:11;;;;;;2261:64;;-1:-1:-1;2261:64:22;;;515:2248;1106:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;2555:206;2663:7;;2752:1;2742:11;;;2555:206;;;1062:4:24;1050:17;;;1032:36;;1116:14;1104:27;;;1099:2;1084:18;;1077:55;1005:18;2555:206:22;864:274:24;1748:46:22;;;:::i;:::-;;1230:32;;;;;;;;1319:42:24;1307:55;;;1289:74;;1277:2;1262:18;1230:32:22;1143:226:24;1748:46:22;3100:19:20;3123:13;;;;;;3122:14;;3168:34;;;;-1:-1:-1;3186:12:20;;3201:1;3186:12;;;;:16;3168:34;3167:97;;;-1:-1:-1;3236:4:20;1465:19:21;:23;;;3208:55:20;;-1:-1:-1;3246:12:20;;;;;:17;3208:55;3146:190;;;;;;;1576:2:24;3146:190:20;;;1558:21:24;1615:2;1595:18;;;1588:30;1654:34;1634:18;;;1627:62;1725:16;1705:18;;;1698:44;1759:19;;3146:190:20;;;;;;;;3346:12;:16;;;;3361:1;3346:16;;;3372:65;;;;3406:13;:20;;;;;;;;3372:65;3461:14;3457:99;;;3507:5;3491:21;;;;;;3531:14;;-1:-1:-1;1941:36:24;;3531:14:20;;1929:2:24;1914:18;3531:14:20;;;;;;;3457:99;3090:472;1748:46:22:o;14:184:24:-;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:656;315:4;344:2;373;362:9;355:21;405:6;399:13;448:6;443:2;432:9;428:18;421:34;473:1;483:140;497:6;494:1;491:13;483:140;;;592:14;;;588:23;;582:30;558:17;;;577:2;554:26;547:66;512:10;;483:140;;;641:6;638:1;635:13;632:91;;;711:1;706:2;697:6;686:9;682:22;678:31;671:42;632:91;-1:-1:-1;775:2:24;763:15;780:66;759:88;744:104;;;;850:2;740:113;;203:656;-1:-1:-1;;;203:656:24:o","linkReferences":{},"immutableReferences":{"39615":[{"start":100,"length":32},{"start":509,"length":32}]}},"methodIdentifiers":{"BUILDER()":"ecfd1b63","get()":"6d4ce63c","initialize()":"8129fc1c","version()":"54fd4d50"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyBuilder\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"name\":\"FlashblockIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"BUILDER\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"custom:upgradeable\":\"@title FlashblockIndex\",\"details\":\"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.\",\"events\":{\"FlashblockIndexUpdated(uint8,uint48)\":{\"params\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The new flashblock index.\"}}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"builder\":\"The address authorized to update the flashblock index.\"}},\"get()\":{\"returns\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The flashblock index.\"}}},\"stateVariables\":{\"_packed\":{\"details\":\"Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks).\"},\"version\":{\"custom:semver\":\"1.0.0\"}},\"version\":1},\"userdoc\":{\"errors\":{\"InvalidCalldata()\":[{\"notice\":\"Thrown when calldata is not exactly 1 byte.\"}],\"OnlyBuilder()\":[{\"notice\":\"Thrown when the caller is not the authorized builder.\"}]},\"events\":{\"FlashblockIndexUpdated(uint8,uint48)\":{\"notice\":\"Emitted when the flashblock index is updated.\"}},\"kind\":\"user\",\"methods\":{\"BUILDER()\":{\"notice\":\"The authorized builder address, set at deploy time.\"},\"constructor\":{\"notice\":\"Constructor.\"},\"get()\":{\"notice\":\"Returns the last stored flashblock index and its associated block number.\"},\"initialize()\":{\"notice\":\"Initializer.\"},\"version()\":{\"notice\":\"Semantic version.\"}},\"notice\":\"Stores the current flashblock index alongside block.number.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/L2/FlashblockIndex.sol\":\"FlashblockIndex\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[\":@lib-keccak/=lib/lib-keccak/contracts/lib/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@rari-capital/solmate/=lib/solmate/\",\":@solady-test/=lib/lib-keccak/lib/solady/test/\",\":@solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":@solady/=lib/solady/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":interfaces/=interfaces/\",\":kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/\",\":lib-keccak/=lib/lib-keccak/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":safe-contracts/=lib/safe-contracts/contracts/\",\":solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":solady/=lib/solady/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"interfaces/universal/ISemver.sol\":{\"keccak256\":\"0xba34562a8026f59886d2e07d1d58d90b9691d00e0788c6263cef6c22740cab44\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0826f998632f83c103c3085bf2e872db79a69022b6d2e0444c83a64ca5283c2a\",\"dweb:/ipfs/QmcJ7PNqkAfKqbjFGRordtAg1v9DvcBSKvdTkVvciLyvQR\"]},\"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x2a21b14ff90012878752f230d3ffd5c3405e5938d06c97a7d89c0a64561d0d66\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3313a8f9bb1f9476857c9050067b31982bf2140b83d84f3bc0cec1f62bbe947f\",\"dweb:/ipfs/Qma17Pk8NRe7aB4UD3jjVxk7nSFaov3eQyv86hcyqkwJRV\"]},\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487\",\"dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG\"]},\"src/L2/FlashblockIndex.sol\":{\"keccak256\":\"0xcf1edffdc342a148ddc1371039e3800d67b6eeba2e401966de4fab10000edbf4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://80f9954baf5b80e57f8a13270c261323cf72e0ea2bf96623b69d9994d1074cf1\",\"dweb:/ipfs/QmQfPLmJzFGrYFGVDvMLkHHgxFgvUEVs1mvoqVwZ2v4Lxs\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"builder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"InvalidCalldata"},{"inputs":[],"type":"error","name":"OnlyBuilder"},{"inputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8","indexed":true},{"internalType":"uint48","name":"blockNumber","type":"uint48","indexed":true}],"type":"event","name":"FlashblockIndexUpdated","anonymous":false},{"inputs":[{"internalType":"uint8","name":"version","type":"uint8","indexed":false}],"type":"event","name":"Initialized","anonymous":false},{"inputs":[],"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"stateMutability":"view","type":"function","name":"BUILDER","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"get","outputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8"},{"internalType":"uint48","name":"blockNumber","type":"uint48"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"initialize"},{"inputs":[],"stateMutability":"view","type":"function","name":"version","outputs":[{"internalType":"string","name":"","type":"string"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"version":1},"userdoc":{"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."},"initialize()":{"notice":"Initializer."},"version()":{"notice":"Semantic version."}},"version":1}},"settings":{"remappings":["@lib-keccak/=lib/lib-keccak/contracts/lib/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@rari-capital/solmate/=lib/solmate/","@solady-test/=lib/lib-keccak/lib/solady/test/","@solady-v0.0.245/=lib/solady-v0.0.245/src/","@solady/=lib/solady/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","interfaces/=interfaces/","kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/","lib-keccak/=lib/lib-keccak/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/","openzeppelin-contracts/=lib/openzeppelin-contracts/","safe-contracts/=lib/safe-contracts/contracts/","solady-v0.0.245/=lib/solady-v0.0.245/src/","solady/=lib/solady/","solmate/=lib/solmate/src/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/L2/FlashblockIndex.sol":"FlashblockIndex"},"evmVersion":"london","libraries":{}},"sources":{"interfaces/universal/ISemver.sol":{"keccak256":"0xba34562a8026f59886d2e07d1d58d90b9691d00e0788c6263cef6c22740cab44","urls":["bzz-raw://0826f998632f83c103c3085bf2e872db79a69022b6d2e0444c83a64ca5283c2a","dweb:/ipfs/QmcJ7PNqkAfKqbjFGRordtAg1v9DvcBSKvdTkVvciLyvQR"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol":{"keccak256":"0x2a21b14ff90012878752f230d3ffd5c3405e5938d06c97a7d89c0a64561d0d66","urls":["bzz-raw://3313a8f9bb1f9476857c9050067b31982bf2140b83d84f3bc0cec1f62bbe947f","dweb:/ipfs/Qma17Pk8NRe7aB4UD3jjVxk7nSFaov3eQyv86hcyqkwJRV"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10","urls":["bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487","dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG"],"license":"MIT"},"src/L2/FlashblockIndex.sol":{"keccak256":"0xcf1edffdc342a148ddc1371039e3800d67b6eeba2e401966de4fab10000edbf4","urls":["bzz-raw://80f9954baf5b80e57f8a13270c261323cf72e0ea2bf96623b69d9994d1074cf1","dweb:/ipfs/QmQfPLmJzFGrYFGVDvMLkHHgxFgvUEVs1mvoqVwZ2v4Lxs"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":39144,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_initialized","offset":0,"slot":"0","type":"t_uint8"},{"astId":39147,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_initializing","offset":1,"slot":"0","type":"t_bool"},{"astId":39618,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_packed","offset":0,"slot":"1","type":"t_uint256"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint8":{"encoding":"inplace","label":"uint8","numberOfBytes":"1"}}},"userdoc":{"version":1,"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."},"initialize()":{"notice":"Initializer."},"version()":{"notice":"Semantic version."}},"events":{"FlashblockIndexUpdated(uint8,uint48)":{"notice":"Emitted when the flashblock index is updated."}},"errors":{"InvalidCalldata()":[{"notice":"Thrown when calldata is not exactly 1 byte."}],"OnlyBuilder()":[{"notice":"Thrown when the caller is not the authorized builder."}]},"notice":"Stores the current flashblock index alongside block.number."},"devdoc":{"version":1,"kind":"dev","details":"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"events":{"FlashblockIndexUpdated(uint8,uint48)":{"params":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The new flashblock index."}}}},"ast":{"absolutePath":"src/L2/FlashblockIndex.sol","id":39732,"exportedSymbols":{"FlashblockIndex":[39731],"ISemver":[9],"Initializable":[39288]},"nodeType":"SourceUnit","src":"32:2732:22","nodes":[{"id":39585,"nodeType":"PragmaDirective","src":"32:23:22","nodes":[],"literals":["solidity","0.8",".15"]},{"id":39587,"nodeType":"ImportDirective","src":"57:86:22","nodes":[],"absolutePath":"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol","file":"@openzeppelin/contracts/proxy/utils/Initializable.sol","nameLocation":"-1:-1:-1","scope":39732,"sourceUnit":39289,"symbolAliases":[{"foreign":{"id":39586,"name":"Initializable","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39288,"src":"66:13:22","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":39589,"nodeType":"ImportDirective","src":"144:59:22","nodes":[],"absolutePath":"interfaces/universal/ISemver.sol","file":"interfaces/universal/ISemver.sol","nameLocation":"-1:-1:-1","scope":39732,"sourceUnit":10,"symbolAliases":[{"foreign":{"id":39588,"name":"ISemver","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"153:7:22","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":39731,"nodeType":"ContractDefinition","src":"515:2248:22","nodes":[{"id":39597,"nodeType":"ErrorDefinition","src":"642:20:22","nodes":[],"documentation":{"id":39595,"nodeType":"StructuredDocumentation","src":"572:65:22","text":"@notice Thrown when the caller is not the authorized builder."},"errorSelector":"357a555d","name":"OnlyBuilder","nameLocation":"648:11:22","parameters":{"id":39596,"nodeType":"ParameterList","parameters":[],"src":"659:2:22"}},{"id":39600,"nodeType":"ErrorDefinition","src":"728:24:22","nodes":[],"documentation":{"id":39598,"nodeType":"StructuredDocumentation","src":"668:55:22","text":"@notice Thrown when calldata is not exactly 1 byte."},"errorSelector":"8129bbcd","name":"InvalidCalldata","nameLocation":"734:15:22","parameters":{"id":39599,"nodeType":"ParameterList","parameters":[],"src":"749:2:22"}},{"id":39607,"nodeType":"EventDefinition","src":"949:88:22","nodes":[],"anonymous":false,"documentation":{"id":39601,"nodeType":"StructuredDocumentation","src":"758:186:22","text":"@notice Emitted when the flashblock index is updated.\n @param flashblockIndex The new flashblock index.\n @param blockNumber The block number at which the index was set."},"eventSelector":"9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf2577","name":"FlashblockIndexUpdated","nameLocation":"955:22:22","parameters":{"id":39606,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39603,"indexed":true,"mutability":"mutable","name":"flashblockIndex","nameLocation":"992:15:22","nodeType":"VariableDeclaration","scope":39607,"src":"978:29:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39602,"name":"uint8","nodeType":"ElementaryTypeName","src":"978:5:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39605,"indexed":true,"mutability":"mutable","name":"blockNumber","nameLocation":"1024:11:22","nodeType":"VariableDeclaration","scope":39607,"src":"1009:26:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39604,"name":"uint48","nodeType":"ElementaryTypeName","src":"1009:6:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"977:59:22"}},{"id":39612,"nodeType":"VariableDeclaration","src":"1106:49:22","nodes":[],"baseFunctions":[8],"constant":true,"documentation":{"id":39608,"nodeType":"StructuredDocumentation","src":"1043:58:22","text":"@notice Semantic version.\n @custom:semver 1.0.0"},"functionSelector":"54fd4d50","mutability":"constant","name":"version","nameLocation":"1138:7:22","overrides":{"id":39610,"nodeType":"OverrideSpecifier","overrides":[],"src":"1129:8:22"},"scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":39609,"name":"string","nodeType":"ElementaryTypeName","src":"1106:6:22","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"value":{"hexValue":"312e302e30","id":39611,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1148:7:22","typeDescriptions":{"typeIdentifier":"t_stringliteral_06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c","typeString":"literal_string \"1.0.0\""},"value":"1.0.0"},"visibility":"public"},{"id":39615,"nodeType":"VariableDeclaration","src":"1230:32:22","nodes":[],"constant":false,"documentation":{"id":39613,"nodeType":"StructuredDocumentation","src":"1162:63:22","text":"@notice The authorized builder address, set at deploy time."},"functionSelector":"ecfd1b63","mutability":"immutable","name":"BUILDER","nameLocation":"1255:7:22","scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39614,"name":"address","nodeType":"ElementaryTypeName","src":"1230:7:22","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"public"},{"id":39618,"nodeType":"VariableDeclaration","src":"1481:23:22","nodes":[],"constant":false,"documentation":{"id":39616,"nodeType":"StructuredDocumentation","src":"1269:207:22","text":"@notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0].\n @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks)."},"mutability":"mutable","name":"_packed","nameLocation":"1497:7:22","scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39617,"name":"uint256","nodeType":"ElementaryTypeName","src":"1481:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"private"},{"id":39632,"nodeType":"FunctionDefinition","src":"1618:95:22","nodes":[],"body":{"id":39631,"nodeType":"Block","src":"1647:66:22","nodes":[],"statements":[{"expression":{"id":39626,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39624,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39615,"src":"1657:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":39625,"name":"builder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39621,"src":"1667:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1657:17:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":39627,"nodeType":"ExpressionStatement","src":"1657:17:22"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":39628,"name":"_disableInitializers","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39287,"src":"1684:20:22","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":39629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1684:22:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39630,"nodeType":"ExpressionStatement","src":"1684:22:22"}]},"documentation":{"id":39619,"nodeType":"StructuredDocumentation","src":"1511:102:22","text":"@notice Constructor.\n @param builder The address authorized to update the flashblock index."},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39622,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39621,"mutability":"mutable","name":"builder","nameLocation":"1638:7:22","nodeType":"VariableDeclaration","scope":39632,"src":"1630:15:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39620,"name":"address","nodeType":"ElementaryTypeName","src":"1630:7:22","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1629:17:22"},"returnParameters":{"id":39623,"nodeType":"ParameterList","parameters":[],"src":"1647:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":39639,"nodeType":"FunctionDefinition","src":"1748:46:22","nodes":[],"body":{"id":39638,"nodeType":"Block","src":"1791:3:22","nodes":[],"statements":[]},"documentation":{"id":39633,"nodeType":"StructuredDocumentation","src":"1719:24:22","text":"@notice Initializer."},"functionSelector":"8129fc1c","implemented":true,"kind":"function","modifiers":[{"id":39636,"kind":"modifierInvocation","modifierName":{"id":39635,"name":"initializer","nodeType":"IdentifierPath","referencedDeclaration":39208,"src":"1779:11:22"},"nodeType":"ModifierInvocation","src":"1779:11:22"}],"name":"initialize","nameLocation":"1757:10:22","parameters":{"id":39634,"nodeType":"ParameterList","parameters":[],"src":"1767:2:22"},"returnParameters":{"id":39637,"nodeType":"ParameterList","parameters":[],"src":"1791:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39701,"nodeType":"FunctionDefinition","src":"2023:309:22","nodes":[],"body":{"id":39700,"nodeType":"Block","src":"2043:289:22","nodes":[],"statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":39646,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":39643,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2057:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39644,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"2057:10:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":39645,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39615,"src":"2071:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"2057:21:22","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39650,"nodeType":"IfStatement","src":"2053:47:22","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39647,"name":"OnlyBuilder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39597,"src":"2087:11:22","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39648,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2087:13:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39649,"nodeType":"RevertStatement","src":"2080:20:22"}},{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39655,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"expression":{"id":39651,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2114:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39652,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2114:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39653,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"2114:15:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"hexValue":"31","id":39654,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2133:1:22","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"2114:20:22","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39659,"nodeType":"IfStatement","src":"2110:50:22","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39656,"name":"InvalidCalldata","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39600,"src":"2143:15:22","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39657,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2143:17:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39658,"nodeType":"RevertStatement","src":"2136:24:22"}},{"expression":{"id":39683,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39660,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39618,"src":"2170:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39682,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"components":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39670,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"expression":{"id":39665,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"2196:5:22","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39666,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"2196:12:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39664,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2189:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39663,"name":"uint48","nodeType":"ElementaryTypeName","src":"2189:6:22","typeDescriptions":{}}},"id":39667,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2189:20:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39662,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2181:7:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39661,"name":"uint256","nodeType":"ElementaryTypeName","src":"2181:7:22","typeDescriptions":{}}},"id":39668,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2181:29:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<<","rightExpression":{"hexValue":"38","id":39669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2214:1:22","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"2181:34:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"id":39671,"isConstant":false,"isInlineArray":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"TupleExpression","src":"2180:36:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"|","rightExpression":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39676,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2233:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39677,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2233:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39679,"indexExpression":{"hexValue":"30","id":39678,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2242:1:22","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"2233:11:22","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39675,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2227:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39674,"name":"uint8","nodeType":"ElementaryTypeName","src":"2227:5:22","typeDescriptions":{}}},"id":39680,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2227:18:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"}],"id":39673,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2219:7:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39672,"name":"uint256","nodeType":"ElementaryTypeName","src":"2219:7:22","typeDescriptions":{}}},"id":39681,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2219:27:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"2180:66:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"2170:76:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":39684,"nodeType":"ExpressionStatement","src":"2170:76:22"},{"eventCall":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39688,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2290:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39689,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2290:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39691,"indexExpression":{"hexValue":"30","id":39690,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2299:1:22","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"2290:11:22","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39687,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2284:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39686,"name":"uint8","nodeType":"ElementaryTypeName","src":"2284:5:22","typeDescriptions":{}}},"id":39692,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2284:18:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},{"arguments":[{"expression":{"id":39695,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"2311:5:22","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39696,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"2311:12:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39694,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2304:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39693,"name":"uint48","nodeType":"ElementaryTypeName","src":"2304:6:22","typeDescriptions":{}}},"id":39697,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2304:20:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"},{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39685,"name":"FlashblockIndexUpdated","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39607,"src":"2261:22:22","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_uint8_$_t_uint48_$returns$__$","typeString":"function (uint8,uint48)"}},"id":39698,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2261:64:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39699,"nodeType":"EmitStatement","src":"2256:69:22"}]},"documentation":{"id":39640,"nodeType":"StructuredDocumentation","src":"1800:218:22","text":"@notice Sets the flashblock index for the current block.\n @dev Calldata must be exactly 1 byte representing the flashblock index (uint8).\n Stores `(block.number << 8) | index` in a single SSTORE."},"implemented":true,"kind":"fallback","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39641,"nodeType":"ParameterList","parameters":[],"src":"2031:2:22"},"returnParameters":{"id":39642,"nodeType":"ParameterList","parameters":[],"src":"2043:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39730,"nodeType":"FunctionDefinition","src":"2555:206:22","nodes":[],"body":{"id":39729,"nodeType":"Block","src":"2636:125:22","nodes":[],"statements":[{"assignments":[39710],"declarations":[{"constant":false,"id":39710,"mutability":"mutable","name":"packed","nameLocation":"2654:6:22","nodeType":"VariableDeclaration","scope":39729,"src":"2646:14:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39709,"name":"uint256","nodeType":"ElementaryTypeName","src":"2646:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39712,"initialValue":{"id":39711,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39618,"src":"2663:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"2646:24:22"},{"expression":{"id":39718,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39713,"name":"flashblockIndex","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39705,"src":"2680:15:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":39716,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39710,"src":"2704:6:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39715,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2698:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39714,"name":"uint8","nodeType":"ElementaryTypeName","src":"2698:5:22","typeDescriptions":{}}},"id":39717,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2698:13:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"src":"2680:31:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"id":39719,"nodeType":"ExpressionStatement","src":"2680:31:22"},{"expression":{"id":39727,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39720,"name":"blockNumber","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39707,"src":"2721:11:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39725,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":39723,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39710,"src":"2742:6:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">>","rightExpression":{"hexValue":"38","id":39724,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2752:1:22","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"2742:11:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39722,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2735:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39721,"name":"uint48","nodeType":"ElementaryTypeName","src":"2735:6:22","typeDescriptions":{}}},"id":39726,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2735:19:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"src":"2721:33:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"id":39728,"nodeType":"ExpressionStatement","src":"2721:33:22"}]},"documentation":{"id":39702,"nodeType":"StructuredDocumentation","src":"2338:212:22","text":"@notice Returns the last stored flashblock index and its associated block number.\n @return flashblockIndex The flashblock index.\n @return blockNumber The block number at which the index was set."},"functionSelector":"6d4ce63c","implemented":true,"kind":"function","modifiers":[],"name":"get","nameLocation":"2564:3:22","parameters":{"id":39703,"nodeType":"ParameterList","parameters":[],"src":"2567:2:22"},"returnParameters":{"id":39708,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39705,"mutability":"mutable","name":"flashblockIndex","nameLocation":"2599:15:22","nodeType":"VariableDeclaration","scope":39730,"src":"2593:21:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39704,"name":"uint8","nodeType":"ElementaryTypeName","src":"2593:5:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39707,"mutability":"mutable","name":"blockNumber","nameLocation":"2623:11:22","nodeType":"VariableDeclaration","scope":39730,"src":"2616:18:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39706,"name":"uint48","nodeType":"ElementaryTypeName","src":"2616:6:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"2592:43:22"},"scope":39731,"stateMutability":"view","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[{"baseName":{"id":39591,"name":"Initializable","nodeType":"IdentifierPath","referencedDeclaration":39288,"src":"543:13:22"},"id":39592,"nodeType":"InheritanceSpecifier","src":"543:13:22"},{"baseName":{"id":39593,"name":"ISemver","nodeType":"IdentifierPath","referencedDeclaration":9,"src":"558:7:22"},"id":39594,"nodeType":"InheritanceSpecifier","src":"558:7:22"}],"canonicalName":"FlashblockIndex","contractDependencies":[],"contractKind":"contract","documentation":{"id":39590,"nodeType":"StructuredDocumentation","src":"205:310:22","text":"@custom:upgradeable\n @title FlashblockIndex\n @notice Stores the current flashblock index alongside block.number.\n @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8).\n Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write."},"fullyImplemented":true,"linearizedBaseContracts":[39731,9,39288],"name":"FlashblockIndex","nameLocation":"524:15:22","scope":39732,"usedErrors":[39597,39600]}],"license":"MIT"},"id":22} \ No newline at end of file diff --git a/crates/bindings/src/l2/flashblock_index.rs b/bindings/rust/src/l2/flashblock_index.rs similarity index 100% rename from crates/bindings/src/l2/flashblock_index.rs rename to bindings/rust/src/l2/flashblock_index.rs diff --git a/crates/bindings/src/l2/mod.rs b/bindings/rust/src/l2/mod.rs similarity index 100% rename from crates/bindings/src/l2/mod.rs rename to bindings/rust/src/l2/mod.rs diff --git a/crates/bindings/src/lib.rs b/bindings/rust/src/lib.rs similarity index 100% rename from crates/bindings/src/lib.rs rename to bindings/rust/src/lib.rs diff --git a/crates/bindings/artifacts/FlashblockIndex.json b/crates/bindings/artifacts/FlashblockIndex.json deleted file mode 100644 index ec080ccb2..000000000 --- a/crates/bindings/artifacts/FlashblockIndex.json +++ /dev/null @@ -1 +0,0 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"builder","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"BUILDER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"get","inputs":[],"outputs":[{"name":"flashblockIndex","type":"uint8","internalType":"uint8"},{"name":"blockNumber","type":"uint48","internalType":"uint48"}],"stateMutability":"view"},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"OnlyBuilder","inputs":[]}],"bytecode":{"object":"0x60a060405234801561001057600080fd5b5060405161025538038061025583398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516101c461009160003960008181604e015261014101526101c46000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461010f578063ecfd1b631461013c575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100a5576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100df576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660008181106100f3576100f3610188565b9091013560f81c4360081b66ffffffffffff0016176000819055005b600054600881901c6040805160ff909316835265ffffffffffff9091166020830152015b60405180910390f35b6101637f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a","sourceMap":"343:1626:19:-:0;;;1016:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1055:17:19;;;343:1626;;14:290:21;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:21;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:21:o;:::-;343:1626:19;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461010f578063ecfd1b631461013c575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100a5576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100df576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660008181106100f3576100f3610188565b9091013560f81c4360081b66ffffffffffff0016176000819055005b600054600881901c6040805160ff909316835265ffffffffffff9091166020830152015b60405180910390f35b6101637f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610133565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a","sourceMap":"343:1626:19:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1342:10;:21;1356:7;1342:21;;1338:47;;1372:13;;;;;;;;;;;;;;1338:47;1418:1;1399:8;:20;1395:50;;1428:17;;;;;;;;;;;;;;1395:50;1518:8;;1527:1;1518:11;;;;;;;:::i;:::-;;;;;;;1481:12;1499:1;1466:34;;;1465:66;1455:7;:76;;;1465:66;1761:206;1799:21;1869:7;1958:1;1948:11;;;1761:206;;;401:4:21;389:17;;;371:36;;455:14;443:27;;;438:2;423:18;;416:55;344:18;1761:206:19;;;;;;;;628:32;;;;;;;;658:42:21;646:55;;;628:74;;616:2;601:18;628:32:19;482:226:21;14:184;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15","linkReferences":{},"immutableReferences":{"39139":[{"start":78,"length":32},{"start":321,"length":32}]}},"methodIdentifiers":{"BUILDER()":"ecfd1b63","get()":"6d4ce63c"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyBuilder\",\"type\":\"error\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"BUILDER\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"builder\":\"The address authorized to update the flashblock index.\"}},\"get()\":{\"returns\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The flashblock index.\"}}},\"stateVariables\":{\"_packed\":{\"details\":\"Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks).\"}},\"title\":\"FlashblockIndex\",\"version\":1},\"userdoc\":{\"errors\":{\"InvalidCalldata()\":[{\"notice\":\"Thrown when calldata is not exactly 1 byte.\"}],\"OnlyBuilder()\":[{\"notice\":\"Thrown when the caller is not the authorized builder.\"}]},\"kind\":\"user\",\"methods\":{\"BUILDER()\":{\"notice\":\"The authorized builder address, set at deploy time.\"},\"constructor\":{\"notice\":\"Constructor.\"},\"get()\":{\"notice\":\"Returns the last stored flashblock index and its associated block number.\"}},\"notice\":\"Stores the current flashblock index alongside block.number.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/L2/FlashblockIndex.sol\":\"FlashblockIndex\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[\":@lib-keccak/=lib/lib-keccak/contracts/lib/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@rari-capital/solmate/=lib/solmate/\",\":@solady-test/=lib/lib-keccak/lib/solady/test/\",\":@solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":@solady/=lib/solady/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":interfaces/=interfaces/\",\":kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/\",\":lib-keccak/=lib/lib-keccak/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":safe-contracts/=lib/safe-contracts/contracts/\",\":solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":solady/=lib/solady/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"src/L2/FlashblockIndex.sol\":{\"keccak256\":\"0x964b79b3878d9c129e5cc81592fe852eb93b87d95283db238ddabd51b93e503f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ed8f0749b8052af49738678cf33a3d9c97ab27e42d1e56681ba5b2c2d804df8\",\"dweb:/ipfs/QmUUx66BhAv5YDWxEM9pPyRqTx8r2sE7ddkKT8TJ1SAixk\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"builder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"InvalidCalldata"},{"inputs":[],"type":"error","name":"OnlyBuilder"},{"inputs":[],"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"stateMutability":"view","type":"function","name":"BUILDER","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"get","outputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8"},{"internalType":"uint48","name":"blockNumber","type":"uint48"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"version":1},"userdoc":{"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."}},"version":1}},"settings":{"remappings":["@lib-keccak/=lib/lib-keccak/contracts/lib/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@rari-capital/solmate/=lib/solmate/","@solady-test/=lib/lib-keccak/lib/solady/test/","@solady-v0.0.245/=lib/solady-v0.0.245/src/","@solady/=lib/solady/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","interfaces/=interfaces/","kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/","lib-keccak/=lib/lib-keccak/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/","openzeppelin-contracts/=lib/openzeppelin-contracts/","safe-contracts/=lib/safe-contracts/contracts/","solady-v0.0.245/=lib/solady-v0.0.245/src/","solady/=lib/solady/","solmate/=lib/solmate/src/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/L2/FlashblockIndex.sol":"FlashblockIndex"},"evmVersion":"london","libraries":{}},"sources":{"src/L2/FlashblockIndex.sol":{"keccak256":"0x964b79b3878d9c129e5cc81592fe852eb93b87d95283db238ddabd51b93e503f","urls":["bzz-raw://0ed8f0749b8052af49738678cf33a3d9c97ab27e42d1e56681ba5b2c2d804df8","dweb:/ipfs/QmUUx66BhAv5YDWxEM9pPyRqTx8r2sE7ddkKT8TJ1SAixk"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":39142,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_packed","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."}},"errors":{"InvalidCalldata()":[{"notice":"Thrown when calldata is not exactly 1 byte."}],"OnlyBuilder()":[{"notice":"Thrown when the caller is not the authorized builder."}]},"notice":"Stores the current flashblock index alongside block.number."},"devdoc":{"version":1,"kind":"dev","details":"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"title":"FlashblockIndex"},"ast":{"absolutePath":"src/L2/FlashblockIndex.sol","id":39231,"exportedSymbols":{"FlashblockIndex":[39230]},"nodeType":"SourceUnit","src":"32:1938:19","nodes":[{"id":39129,"nodeType":"PragmaDirective","src":"32:23:19","nodes":[],"literals":["solidity","0.8",".15"]},{"id":39230,"nodeType":"ContractDefinition","src":"343:1626:19","nodes":[{"id":39133,"nodeType":"ErrorDefinition","src":"444:20:19","nodes":[],"documentation":{"id":39131,"nodeType":"StructuredDocumentation","src":"374:65:19","text":"@notice Thrown when the caller is not the authorized builder."},"errorSelector":"357a555d","name":"OnlyBuilder","nameLocation":"450:11:19","parameters":{"id":39132,"nodeType":"ParameterList","parameters":[],"src":"461:2:19"}},{"id":39136,"nodeType":"ErrorDefinition","src":"530:24:19","nodes":[],"documentation":{"id":39134,"nodeType":"StructuredDocumentation","src":"470:55:19","text":"@notice Thrown when calldata is not exactly 1 byte."},"errorSelector":"8129bbcd","name":"InvalidCalldata","nameLocation":"536:15:19","parameters":{"id":39135,"nodeType":"ParameterList","parameters":[],"src":"551:2:19"}},{"id":39139,"nodeType":"VariableDeclaration","src":"628:32:19","nodes":[],"constant":false,"documentation":{"id":39137,"nodeType":"StructuredDocumentation","src":"560:63:19","text":"@notice The authorized builder address, set at deploy time."},"functionSelector":"ecfd1b63","mutability":"immutable","name":"BUILDER","nameLocation":"653:7:19","scope":39230,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39138,"name":"address","nodeType":"ElementaryTypeName","src":"628:7:19","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"public"},{"id":39142,"nodeType":"VariableDeclaration","src":"879:23:19","nodes":[],"constant":false,"documentation":{"id":39140,"nodeType":"StructuredDocumentation","src":"667:207:19","text":"@notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0].\n @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks)."},"mutability":"mutable","name":"_packed","nameLocation":"895:7:19","scope":39230,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39141,"name":"uint256","nodeType":"ElementaryTypeName","src":"879:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"private"},{"id":39153,"nodeType":"FunctionDefinition","src":"1016:63:19","nodes":[],"body":{"id":39152,"nodeType":"Block","src":"1045:34:19","nodes":[],"statements":[{"expression":{"id":39150,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39148,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39139,"src":"1055:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":39149,"name":"builder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39145,"src":"1065:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1055:17:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":39151,"nodeType":"ExpressionStatement","src":"1055:17:19"}]},"documentation":{"id":39143,"nodeType":"StructuredDocumentation","src":"909:102:19","text":"@notice Constructor.\n @param builder The address authorized to update the flashblock index."},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39146,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39145,"mutability":"mutable","name":"builder","nameLocation":"1036:7:19","nodeType":"VariableDeclaration","scope":39153,"src":"1028:15:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39144,"name":"address","nodeType":"ElementaryTypeName","src":"1028:7:19","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1027:17:19"},"returnParameters":{"id":39147,"nodeType":"ParameterList","parameters":[],"src":"1045:0:19"},"scope":39230,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":39200,"nodeType":"FunctionDefinition","src":"1308:230:19","nodes":[],"body":{"id":39199,"nodeType":"Block","src":"1328:210:19","nodes":[],"statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":39160,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":39157,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1342:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39158,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"1342:10:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":39159,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39139,"src":"1356:7:19","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1342:21:19","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39164,"nodeType":"IfStatement","src":"1338:47:19","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39161,"name":"OnlyBuilder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39133,"src":"1372:11:19","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1372:13:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39163,"nodeType":"RevertStatement","src":"1365:20:19"}},{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39169,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"expression":{"id":39165,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1399:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39166,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"1399:8:19","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39167,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1399:15:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"hexValue":"31","id":39168,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1418:1:19","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"1399:20:19","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39173,"nodeType":"IfStatement","src":"1395:50:19","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39170,"name":"InvalidCalldata","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39136,"src":"1428:15:19","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39171,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1428:17:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39172,"nodeType":"RevertStatement","src":"1421:24:19"}},{"expression":{"id":39197,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39174,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39142,"src":"1455:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39196,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"components":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39184,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"expression":{"id":39179,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"1481:5:19","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39180,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"1481:12:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39178,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1474:6:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39177,"name":"uint48","nodeType":"ElementaryTypeName","src":"1474:6:19","typeDescriptions":{}}},"id":39181,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1474:20:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39176,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1466:7:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39175,"name":"uint256","nodeType":"ElementaryTypeName","src":"1466:7:19","typeDescriptions":{}}},"id":39182,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1466:29:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<<","rightExpression":{"hexValue":"38","id":39183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1499:1:19","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"1466:34:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"id":39185,"isConstant":false,"isInlineArray":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"TupleExpression","src":"1465:36:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"|","rightExpression":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39190,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"1518:3:19","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39191,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"1518:8:19","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39193,"indexExpression":{"hexValue":"30","id":39192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1527:1:19","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"1518:11:19","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39189,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1512:5:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39188,"name":"uint8","nodeType":"ElementaryTypeName","src":"1512:5:19","typeDescriptions":{}}},"id":39194,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1512:18:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"}],"id":39187,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1504:7:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39186,"name":"uint256","nodeType":"ElementaryTypeName","src":"1504:7:19","typeDescriptions":{}}},"id":39195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1504:27:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"1465:66:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"1455:76:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":39198,"nodeType":"ExpressionStatement","src":"1455:76:19"}]},"documentation":{"id":39154,"nodeType":"StructuredDocumentation","src":"1085:218:19","text":"@notice Sets the flashblock index for the current block.\n @dev Calldata must be exactly 1 byte representing the flashblock index (uint8).\n Stores `(block.number << 8) | index` in a single SSTORE."},"implemented":true,"kind":"fallback","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39155,"nodeType":"ParameterList","parameters":[],"src":"1316:2:19"},"returnParameters":{"id":39156,"nodeType":"ParameterList","parameters":[],"src":"1328:0:19"},"scope":39230,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39229,"nodeType":"FunctionDefinition","src":"1761:206:19","nodes":[],"body":{"id":39228,"nodeType":"Block","src":"1842:125:19","nodes":[],"statements":[{"assignments":[39209],"declarations":[{"constant":false,"id":39209,"mutability":"mutable","name":"packed","nameLocation":"1860:6:19","nodeType":"VariableDeclaration","scope":39228,"src":"1852:14:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39208,"name":"uint256","nodeType":"ElementaryTypeName","src":"1852:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39211,"initialValue":{"id":39210,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39142,"src":"1869:7:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1852:24:19"},{"expression":{"id":39217,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39212,"name":"flashblockIndex","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39204,"src":"1886:15:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":39215,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39209,"src":"1910:6:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39214,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1904:5:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39213,"name":"uint8","nodeType":"ElementaryTypeName","src":"1904:5:19","typeDescriptions":{}}},"id":39216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1904:13:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"src":"1886:31:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"id":39218,"nodeType":"ExpressionStatement","src":"1886:31:19"},{"expression":{"id":39226,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39219,"name":"blockNumber","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39206,"src":"1927:11:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39224,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":39222,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39209,"src":"1948:6:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">>","rightExpression":{"hexValue":"38","id":39223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1958:1:19","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"1948:11:19","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39221,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1941:6:19","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39220,"name":"uint48","nodeType":"ElementaryTypeName","src":"1941:6:19","typeDescriptions":{}}},"id":39225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1941:19:19","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"src":"1927:33:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"id":39227,"nodeType":"ExpressionStatement","src":"1927:33:19"}]},"documentation":{"id":39201,"nodeType":"StructuredDocumentation","src":"1544:212:19","text":"@notice Returns the last stored flashblock index and its associated block number.\n @return flashblockIndex The flashblock index.\n @return blockNumber The block number at which the index was set."},"functionSelector":"6d4ce63c","implemented":true,"kind":"function","modifiers":[],"name":"get","nameLocation":"1770:3:19","parameters":{"id":39202,"nodeType":"ParameterList","parameters":[],"src":"1773:2:19"},"returnParameters":{"id":39207,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39204,"mutability":"mutable","name":"flashblockIndex","nameLocation":"1805:15:19","nodeType":"VariableDeclaration","scope":39229,"src":"1799:21:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39203,"name":"uint8","nodeType":"ElementaryTypeName","src":"1799:5:19","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39206,"mutability":"mutable","name":"blockNumber","nameLocation":"1829:11:19","nodeType":"VariableDeclaration","scope":39229,"src":"1822:18:19","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39205,"name":"uint48","nodeType":"ElementaryTypeName","src":"1822:6:19","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"1798:43:19"},"scope":39230,"stateMutability":"view","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"FlashblockIndex","contractDependencies":[],"contractKind":"contract","documentation":{"id":39130,"nodeType":"StructuredDocumentation","src":"57:286:19","text":"@title FlashblockIndex\n @notice Stores the current flashblock index alongside block.number.\n @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8).\n Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write."},"fullyImplemented":true,"linearizedBaseContracts":[39230],"name":"FlashblockIndex","nameLocation":"352:15:19","scope":39231,"usedErrors":[39133,39136]}],"license":"MIT"},"id":19} \ No newline at end of file From 364e9ce3139e971599ebbe585b51e4322e783024 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Wed, 4 Mar 2026 16:47:51 +0000 Subject: [PATCH 11/18] chore: strip binding artifacts and add justfile recipes for bindings --- bindings/rust/artifacts/FlashblockIndex.json | 119 ++++++++++++++++++- justfile | 80 ++++++++++++- 2 files changed, 197 insertions(+), 2 deletions(-) diff --git a/bindings/rust/artifacts/FlashblockIndex.json b/bindings/rust/artifacts/FlashblockIndex.json index 1e5e73e13..aa15b3d9a 100644 --- a/bindings/rust/artifacts/FlashblockIndex.json +++ b/bindings/rust/artifacts/FlashblockIndex.json @@ -1 +1,118 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"builder","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"fallback","stateMutability":"nonpayable"},{"type":"function","name":"BUILDER","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"get","inputs":[],"outputs":[{"name":"flashblockIndex","type":"uint8","internalType":"uint8"},{"name":"blockNumber","type":"uint48","internalType":"uint48"}],"stateMutability":"view"},{"type":"function","name":"initialize","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"version","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"event","name":"FlashblockIndexUpdated","inputs":[{"name":"flashblockIndex","type":"uint8","indexed":true,"internalType":"uint8"},{"name":"blockNumber","type":"uint48","indexed":true,"internalType":"uint48"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint8","indexed":false,"internalType":"uint8"}],"anonymous":false},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"OnlyBuilder","inputs":[]}],"bytecode":{"object":"0x60a060405234801561001057600080fd5b506040516105dc3803806105dc83398101604081905261002f9161010a565b6001600160a01b03811660805261004461004a565b5061013a565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015610108576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011c57600080fd5b81516001600160a01b038116811461013357600080fd5b9392505050565b60805161048161015b60003960008181606401526101fd01526104816000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a","sourceMap":"515:2248:22:-:0;;;1618:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1657:17:22;;;;1684:22;:20;:22::i;:::-;1618:95;515:2248;;5366:279:20;5434:13;;;;;;;5433:14;5425:66;;;;-1:-1:-1;;;5425:66:20;;511:2:24;5425:66:20;;;493:21:24;550:2;530:18;;;523:30;589:34;569:18;;;562:62;-1:-1:-1;;;640:18:24;;;633:37;687:19;;5425:66:20;;;;;;;;5505:12;;5520:15;5505:12;;;:30;5501:138;;;5551:12;:30;;-1:-1:-1;;5551:30:20;5566:15;5551:30;;;;;;5600:28;;859:36:24;;;5600:28:20;;847:2:24;832:18;5600:28:20;;;;;;;5501:138;5366:279::o;14:290:24:-;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:24;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:24:o;717:184::-;515:2248:22;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a","sourceMap":"515:2248:22:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2057:10;:21;2071:7;2057:21;;2053:47;;2087:13;;;;;;;;;;;;;;2053:47;2133:1;2114:8;:20;2110:50;;2143:17;;;;;;;;;;;;;;2110:50;2233:8;;2242:1;2233:11;;;;;;;:::i;:::-;;;;;;;2196:12;2214:1;2181:34;;;;;2180:66;;;;2170:7;:76;2181:29;;;-1:-1:-1;2290:8:22;;;;:11;;;;:::i;:::-;2261:64;;2290:11;;;;;;2261:64;;-1:-1:-1;2261:64:22;;;515:2248;1106:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;2555:206;2663:7;;2752:1;2742:11;;;2555:206;;;1062:4:24;1050:17;;;1032:36;;1116:14;1104:27;;;1099:2;1084:18;;1077:55;1005:18;2555:206:22;864:274:24;1748:46:22;;;:::i;:::-;;1230:32;;;;;;;;1319:42:24;1307:55;;;1289:74;;1277:2;1262:18;1230:32:22;1143:226:24;1748:46:22;3100:19:20;3123:13;;;;;;3122:14;;3168:34;;;;-1:-1:-1;3186:12:20;;3201:1;3186:12;;;;:16;3168:34;3167:97;;;-1:-1:-1;3236:4:20;1465:19:21;:23;;;3208:55:20;;-1:-1:-1;3246:12:20;;;;;:17;3208:55;3146:190;;;;;;;1576:2:24;3146:190:20;;;1558:21:24;1615:2;1595:18;;;1588:30;1654:34;1634:18;;;1627:62;1725:16;1705:18;;;1698:44;1759:19;;3146:190:20;;;;;;;;3346:12;:16;;;;3361:1;3346:16;;;3372:65;;;;3406:13;:20;;;;;;;;3372:65;3461:14;3457:99;;;3507:5;3491:21;;;;;;3531:14;;-1:-1:-1;1941:36:24;;3531:14:20;;1929:2:24;1914:18;3531:14:20;;;;;;;3457:99;3090:472;1748:46:22:o;14:184:24:-;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:656;315:4;344:2;373;362:9;355:21;405:6;399:13;448:6;443:2;432:9;428:18;421:34;473:1;483:140;497:6;494:1;491:13;483:140;;;592:14;;;588:23;;582:30;558:17;;;577:2;554:26;547:66;512:10;;483:140;;;641:6;638:1;635:13;632:91;;;711:1;706:2;697:6;686:9;682:22;678:31;671:42;632:91;-1:-1:-1;775:2:24;763:15;780:66;759:88;744:104;;;;850:2;740:113;;203:656;-1:-1:-1;;;203:656:24:o","linkReferences":{},"immutableReferences":{"39615":[{"start":100,"length":32},{"start":509,"length":32}]}},"methodIdentifiers":{"BUILDER()":"ecfd1b63","get()":"6d4ce63c","initialize()":"8129fc1c","version()":"54fd4d50"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"builder\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyBuilder\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"indexed\":true,\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"name\":\"FlashblockIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"BUILDER\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"flashblockIndex\",\"type\":\"uint8\"},{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"custom:upgradeable\":\"@title FlashblockIndex\",\"details\":\"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.\",\"events\":{\"FlashblockIndexUpdated(uint8,uint48)\":{\"params\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The new flashblock index.\"}}},\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"builder\":\"The address authorized to update the flashblock index.\"}},\"get()\":{\"returns\":{\"blockNumber\":\"The block number at which the index was set.\",\"flashblockIndex\":\"The flashblock index.\"}}},\"stateVariables\":{\"_packed\":{\"details\":\"Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks).\"},\"version\":{\"custom:semver\":\"1.0.0\"}},\"version\":1},\"userdoc\":{\"errors\":{\"InvalidCalldata()\":[{\"notice\":\"Thrown when calldata is not exactly 1 byte.\"}],\"OnlyBuilder()\":[{\"notice\":\"Thrown when the caller is not the authorized builder.\"}]},\"events\":{\"FlashblockIndexUpdated(uint8,uint48)\":{\"notice\":\"Emitted when the flashblock index is updated.\"}},\"kind\":\"user\",\"methods\":{\"BUILDER()\":{\"notice\":\"The authorized builder address, set at deploy time.\"},\"constructor\":{\"notice\":\"Constructor.\"},\"get()\":{\"notice\":\"Returns the last stored flashblock index and its associated block number.\"},\"initialize()\":{\"notice\":\"Initializer.\"},\"version()\":{\"notice\":\"Semantic version.\"}},\"notice\":\"Stores the current flashblock index alongside block.number.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/L2/FlashblockIndex.sol\":\"FlashblockIndex\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[\":@lib-keccak/=lib/lib-keccak/contracts/lib/\",\":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/\",\":@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@rari-capital/solmate/=lib/solmate/\",\":@solady-test/=lib/lib-keccak/lib/solady/test/\",\":@solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":@solady/=lib/solady/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":interfaces/=interfaces/\",\":kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/\",\":lib-keccak/=lib/lib-keccak/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":safe-contracts/=lib/safe-contracts/contracts/\",\":solady-v0.0.245/=lib/solady-v0.0.245/src/\",\":solady/=lib/solady/\",\":solmate/=lib/solmate/src/\"]},\"sources\":{\"interfaces/universal/ISemver.sol\":{\"keccak256\":\"0xba34562a8026f59886d2e07d1d58d90b9691d00e0788c6263cef6c22740cab44\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0826f998632f83c103c3085bf2e872db79a69022b6d2e0444c83a64ca5283c2a\",\"dweb:/ipfs/QmcJ7PNqkAfKqbjFGRordtAg1v9DvcBSKvdTkVvciLyvQR\"]},\"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol\":{\"keccak256\":\"0x2a21b14ff90012878752f230d3ffd5c3405e5938d06c97a7d89c0a64561d0d66\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3313a8f9bb1f9476857c9050067b31982bf2140b83d84f3bc0cec1f62bbe947f\",\"dweb:/ipfs/Qma17Pk8NRe7aB4UD3jjVxk7nSFaov3eQyv86hcyqkwJRV\"]},\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487\",\"dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG\"]},\"src/L2/FlashblockIndex.sol\":{\"keccak256\":\"0xcf1edffdc342a148ddc1371039e3800d67b6eeba2e401966de4fab10000edbf4\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://80f9954baf5b80e57f8a13270c261323cf72e0ea2bf96623b69d9994d1074cf1\",\"dweb:/ipfs/QmQfPLmJzFGrYFGVDvMLkHHgxFgvUEVs1mvoqVwZ2v4Lxs\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"builder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"type":"error","name":"InvalidCalldata"},{"inputs":[],"type":"error","name":"OnlyBuilder"},{"inputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8","indexed":true},{"internalType":"uint48","name":"blockNumber","type":"uint48","indexed":true}],"type":"event","name":"FlashblockIndexUpdated","anonymous":false},{"inputs":[{"internalType":"uint8","name":"version","type":"uint8","indexed":false}],"type":"event","name":"Initialized","anonymous":false},{"inputs":[],"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"stateMutability":"view","type":"function","name":"BUILDER","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"view","type":"function","name":"get","outputs":[{"internalType":"uint8","name":"flashblockIndex","type":"uint8"},{"internalType":"uint48","name":"blockNumber","type":"uint48"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"initialize"},{"inputs":[],"stateMutability":"view","type":"function","name":"version","outputs":[{"internalType":"string","name":"","type":"string"}]}],"devdoc":{"kind":"dev","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"version":1},"userdoc":{"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."},"initialize()":{"notice":"Initializer."},"version()":{"notice":"Semantic version."}},"version":1}},"settings":{"remappings":["@lib-keccak/=lib/lib-keccak/contracts/lib/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@rari-capital/solmate/=lib/solmate/","@solady-test/=lib/lib-keccak/lib/solady/test/","@solady-v0.0.245/=lib/solady-v0.0.245/src/","@solady/=lib/solady/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","interfaces/=interfaces/","kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/","lib-keccak/=lib/lib-keccak/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/","openzeppelin-contracts/=lib/openzeppelin-contracts/","safe-contracts/=lib/safe-contracts/contracts/","solady-v0.0.245/=lib/solady-v0.0.245/src/","solady/=lib/solady/","solmate/=lib/solmate/src/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/L2/FlashblockIndex.sol":"FlashblockIndex"},"evmVersion":"london","libraries":{}},"sources":{"interfaces/universal/ISemver.sol":{"keccak256":"0xba34562a8026f59886d2e07d1d58d90b9691d00e0788c6263cef6c22740cab44","urls":["bzz-raw://0826f998632f83c103c3085bf2e872db79a69022b6d2e0444c83a64ca5283c2a","dweb:/ipfs/QmcJ7PNqkAfKqbjFGRordtAg1v9DvcBSKvdTkVvciLyvQR"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol":{"keccak256":"0x2a21b14ff90012878752f230d3ffd5c3405e5938d06c97a7d89c0a64561d0d66","urls":["bzz-raw://3313a8f9bb1f9476857c9050067b31982bf2140b83d84f3bc0cec1f62bbe947f","dweb:/ipfs/Qma17Pk8NRe7aB4UD3jjVxk7nSFaov3eQyv86hcyqkwJRV"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10","urls":["bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487","dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG"],"license":"MIT"},"src/L2/FlashblockIndex.sol":{"keccak256":"0xcf1edffdc342a148ddc1371039e3800d67b6eeba2e401966de4fab10000edbf4","urls":["bzz-raw://80f9954baf5b80e57f8a13270c261323cf72e0ea2bf96623b69d9994d1074cf1","dweb:/ipfs/QmQfPLmJzFGrYFGVDvMLkHHgxFgvUEVs1mvoqVwZ2v4Lxs"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":39144,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_initialized","offset":0,"slot":"0","type":"t_uint8"},{"astId":39147,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_initializing","offset":1,"slot":"0","type":"t_bool"},{"astId":39618,"contract":"src/L2/FlashblockIndex.sol:FlashblockIndex","label":"_packed","offset":0,"slot":"1","type":"t_uint256"}],"types":{"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint8":{"encoding":"inplace","label":"uint8","numberOfBytes":"1"}}},"userdoc":{"version":1,"kind":"user","methods":{"BUILDER()":{"notice":"The authorized builder address, set at deploy time."},"constructor":{"notice":"Constructor."},"get()":{"notice":"Returns the last stored flashblock index and its associated block number."},"initialize()":{"notice":"Initializer."},"version()":{"notice":"Semantic version."}},"events":{"FlashblockIndexUpdated(uint8,uint48)":{"notice":"Emitted when the flashblock index is updated."}},"errors":{"InvalidCalldata()":[{"notice":"Thrown when calldata is not exactly 1 byte."}],"OnlyBuilder()":[{"notice":"Thrown when the caller is not the authorized builder."}]},"notice":"Stores the current flashblock index alongside block.number."},"devdoc":{"version":1,"kind":"dev","details":"The builder calls this via fallback with 1 byte of calldata (the index as uint8). Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write.","methods":{"constructor":{"params":{"builder":"The address authorized to update the flashblock index."}},"get()":{"returns":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The flashblock index."}}},"events":{"FlashblockIndexUpdated(uint8,uint48)":{"params":{"blockNumber":"The block number at which the index was set.","flashblockIndex":"The new flashblock index."}}}},"ast":{"absolutePath":"src/L2/FlashblockIndex.sol","id":39732,"exportedSymbols":{"FlashblockIndex":[39731],"ISemver":[9],"Initializable":[39288]},"nodeType":"SourceUnit","src":"32:2732:22","nodes":[{"id":39585,"nodeType":"PragmaDirective","src":"32:23:22","nodes":[],"literals":["solidity","0.8",".15"]},{"id":39587,"nodeType":"ImportDirective","src":"57:86:22","nodes":[],"absolutePath":"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol","file":"@openzeppelin/contracts/proxy/utils/Initializable.sol","nameLocation":"-1:-1:-1","scope":39732,"sourceUnit":39289,"symbolAliases":[{"foreign":{"id":39586,"name":"Initializable","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39288,"src":"66:13:22","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":39589,"nodeType":"ImportDirective","src":"144:59:22","nodes":[],"absolutePath":"interfaces/universal/ISemver.sol","file":"interfaces/universal/ISemver.sol","nameLocation":"-1:-1:-1","scope":39732,"sourceUnit":10,"symbolAliases":[{"foreign":{"id":39588,"name":"ISemver","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"153:7:22","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":39731,"nodeType":"ContractDefinition","src":"515:2248:22","nodes":[{"id":39597,"nodeType":"ErrorDefinition","src":"642:20:22","nodes":[],"documentation":{"id":39595,"nodeType":"StructuredDocumentation","src":"572:65:22","text":"@notice Thrown when the caller is not the authorized builder."},"errorSelector":"357a555d","name":"OnlyBuilder","nameLocation":"648:11:22","parameters":{"id":39596,"nodeType":"ParameterList","parameters":[],"src":"659:2:22"}},{"id":39600,"nodeType":"ErrorDefinition","src":"728:24:22","nodes":[],"documentation":{"id":39598,"nodeType":"StructuredDocumentation","src":"668:55:22","text":"@notice Thrown when calldata is not exactly 1 byte."},"errorSelector":"8129bbcd","name":"InvalidCalldata","nameLocation":"734:15:22","parameters":{"id":39599,"nodeType":"ParameterList","parameters":[],"src":"749:2:22"}},{"id":39607,"nodeType":"EventDefinition","src":"949:88:22","nodes":[],"anonymous":false,"documentation":{"id":39601,"nodeType":"StructuredDocumentation","src":"758:186:22","text":"@notice Emitted when the flashblock index is updated.\n @param flashblockIndex The new flashblock index.\n @param blockNumber The block number at which the index was set."},"eventSelector":"9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf2577","name":"FlashblockIndexUpdated","nameLocation":"955:22:22","parameters":{"id":39606,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39603,"indexed":true,"mutability":"mutable","name":"flashblockIndex","nameLocation":"992:15:22","nodeType":"VariableDeclaration","scope":39607,"src":"978:29:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39602,"name":"uint8","nodeType":"ElementaryTypeName","src":"978:5:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39605,"indexed":true,"mutability":"mutable","name":"blockNumber","nameLocation":"1024:11:22","nodeType":"VariableDeclaration","scope":39607,"src":"1009:26:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39604,"name":"uint48","nodeType":"ElementaryTypeName","src":"1009:6:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"977:59:22"}},{"id":39612,"nodeType":"VariableDeclaration","src":"1106:49:22","nodes":[],"baseFunctions":[8],"constant":true,"documentation":{"id":39608,"nodeType":"StructuredDocumentation","src":"1043:58:22","text":"@notice Semantic version.\n @custom:semver 1.0.0"},"functionSelector":"54fd4d50","mutability":"constant","name":"version","nameLocation":"1138:7:22","overrides":{"id":39610,"nodeType":"OverrideSpecifier","overrides":[],"src":"1129:8:22"},"scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":39609,"name":"string","nodeType":"ElementaryTypeName","src":"1106:6:22","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"value":{"hexValue":"312e302e30","id":39611,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1148:7:22","typeDescriptions":{"typeIdentifier":"t_stringliteral_06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c","typeString":"literal_string \"1.0.0\""},"value":"1.0.0"},"visibility":"public"},{"id":39615,"nodeType":"VariableDeclaration","src":"1230:32:22","nodes":[],"constant":false,"documentation":{"id":39613,"nodeType":"StructuredDocumentation","src":"1162:63:22","text":"@notice The authorized builder address, set at deploy time."},"functionSelector":"ecfd1b63","mutability":"immutable","name":"BUILDER","nameLocation":"1255:7:22","scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39614,"name":"address","nodeType":"ElementaryTypeName","src":"1230:7:22","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"public"},{"id":39618,"nodeType":"VariableDeclaration","src":"1481:23:22","nodes":[],"constant":false,"documentation":{"id":39616,"nodeType":"StructuredDocumentation","src":"1269:207:22","text":"@notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0].\n @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks)."},"mutability":"mutable","name":"_packed","nameLocation":"1497:7:22","scope":39731,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39617,"name":"uint256","nodeType":"ElementaryTypeName","src":"1481:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"private"},{"id":39632,"nodeType":"FunctionDefinition","src":"1618:95:22","nodes":[],"body":{"id":39631,"nodeType":"Block","src":"1647:66:22","nodes":[],"statements":[{"expression":{"id":39626,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39624,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39615,"src":"1657:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":39625,"name":"builder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39621,"src":"1667:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"1657:17:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":39627,"nodeType":"ExpressionStatement","src":"1657:17:22"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":39628,"name":"_disableInitializers","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39287,"src":"1684:20:22","typeDescriptions":{"typeIdentifier":"t_function_internal_nonpayable$__$returns$__$","typeString":"function ()"}},"id":39629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1684:22:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39630,"nodeType":"ExpressionStatement","src":"1684:22:22"}]},"documentation":{"id":39619,"nodeType":"StructuredDocumentation","src":"1511:102:22","text":"@notice Constructor.\n @param builder The address authorized to update the flashblock index."},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39622,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39621,"mutability":"mutable","name":"builder","nameLocation":"1638:7:22","nodeType":"VariableDeclaration","scope":39632,"src":"1630:15:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39620,"name":"address","nodeType":"ElementaryTypeName","src":"1630:7:22","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"1629:17:22"},"returnParameters":{"id":39623,"nodeType":"ParameterList","parameters":[],"src":"1647:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":39639,"nodeType":"FunctionDefinition","src":"1748:46:22","nodes":[],"body":{"id":39638,"nodeType":"Block","src":"1791:3:22","nodes":[],"statements":[]},"documentation":{"id":39633,"nodeType":"StructuredDocumentation","src":"1719:24:22","text":"@notice Initializer."},"functionSelector":"8129fc1c","implemented":true,"kind":"function","modifiers":[{"id":39636,"kind":"modifierInvocation","modifierName":{"id":39635,"name":"initializer","nodeType":"IdentifierPath","referencedDeclaration":39208,"src":"1779:11:22"},"nodeType":"ModifierInvocation","src":"1779:11:22"}],"name":"initialize","nameLocation":"1757:10:22","parameters":{"id":39634,"nodeType":"ParameterList","parameters":[],"src":"1767:2:22"},"returnParameters":{"id":39637,"nodeType":"ParameterList","parameters":[],"src":"1791:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39701,"nodeType":"FunctionDefinition","src":"2023:309:22","nodes":[],"body":{"id":39700,"nodeType":"Block","src":"2043:289:22","nodes":[],"statements":[{"condition":{"commonType":{"typeIdentifier":"t_address","typeString":"address"},"id":39646,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":39643,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2057:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39644,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"2057:10:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"id":39645,"name":"BUILDER","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39615,"src":"2071:7:22","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"2057:21:22","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39650,"nodeType":"IfStatement","src":"2053:47:22","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39647,"name":"OnlyBuilder","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39597,"src":"2087:11:22","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39648,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2087:13:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39649,"nodeType":"RevertStatement","src":"2080:20:22"}},{"condition":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39655,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"expression":{"id":39651,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2114:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39652,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2114:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39653,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"2114:15:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"!=","rightExpression":{"hexValue":"31","id":39654,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2133:1:22","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"2114:20:22","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":39659,"nodeType":"IfStatement","src":"2110:50:22","trueBody":{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":39656,"name":"InvalidCalldata","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39600,"src":"2143:15:22","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":39657,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2143:17:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39658,"nodeType":"RevertStatement","src":"2136:24:22"}},{"expression":{"id":39683,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39660,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39618,"src":"2170:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39682,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"components":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39670,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"arguments":[{"expression":{"id":39665,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"2196:5:22","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39666,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"2196:12:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39664,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2189:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39663,"name":"uint48","nodeType":"ElementaryTypeName","src":"2189:6:22","typeDescriptions":{}}},"id":39667,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2189:20:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39662,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2181:7:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39661,"name":"uint256","nodeType":"ElementaryTypeName","src":"2181:7:22","typeDescriptions":{}}},"id":39668,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2181:29:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"<<","rightExpression":{"hexValue":"38","id":39669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2214:1:22","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"2181:34:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"id":39671,"isConstant":false,"isInlineArray":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"TupleExpression","src":"2180:36:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"|","rightExpression":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39676,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2233:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39677,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2233:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39679,"indexExpression":{"hexValue":"30","id":39678,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2242:1:22","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"2233:11:22","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39675,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2227:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39674,"name":"uint8","nodeType":"ElementaryTypeName","src":"2227:5:22","typeDescriptions":{}}},"id":39680,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2227:18:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"}],"id":39673,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2219:7:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":39672,"name":"uint256","nodeType":"ElementaryTypeName","src":"2219:7:22","typeDescriptions":{}}},"id":39681,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2219:27:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"2180:66:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"2170:76:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":39684,"nodeType":"ExpressionStatement","src":"2170:76:22"},{"eventCall":{"arguments":[{"arguments":[{"baseExpression":{"expression":{"id":39688,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"2290:3:22","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":39689,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"data","nodeType":"MemberAccess","src":"2290:8:22","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},"id":39691,"indexExpression":{"hexValue":"30","id":39690,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2299:1:22","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"2290:11:22","typeDescriptions":{"typeIdentifier":"t_bytes1","typeString":"bytes1"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes1","typeString":"bytes1"}],"id":39687,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2284:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39686,"name":"uint8","nodeType":"ElementaryTypeName","src":"2284:5:22","typeDescriptions":{}}},"id":39692,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2284:18:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},{"arguments":[{"expression":{"id":39695,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"2311:5:22","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":39696,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"number","nodeType":"MemberAccess","src":"2311:12:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39694,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2304:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39693,"name":"uint48","nodeType":"ElementaryTypeName","src":"2304:6:22","typeDescriptions":{}}},"id":39697,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2304:20:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"},{"typeIdentifier":"t_uint48","typeString":"uint48"}],"id":39685,"name":"FlashblockIndexUpdated","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39607,"src":"2261:22:22","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_uint8_$_t_uint48_$returns$__$","typeString":"function (uint8,uint48)"}},"id":39698,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2261:64:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":39699,"nodeType":"EmitStatement","src":"2256:69:22"}]},"documentation":{"id":39640,"nodeType":"StructuredDocumentation","src":"1800:218:22","text":"@notice Sets the flashblock index for the current block.\n @dev Calldata must be exactly 1 byte representing the flashblock index (uint8).\n Stores `(block.number << 8) | index` in a single SSTORE."},"implemented":true,"kind":"fallback","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":39641,"nodeType":"ParameterList","parameters":[],"src":"2031:2:22"},"returnParameters":{"id":39642,"nodeType":"ParameterList","parameters":[],"src":"2043:0:22"},"scope":39731,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":39730,"nodeType":"FunctionDefinition","src":"2555:206:22","nodes":[],"body":{"id":39729,"nodeType":"Block","src":"2636:125:22","nodes":[],"statements":[{"assignments":[39710],"declarations":[{"constant":false,"id":39710,"mutability":"mutable","name":"packed","nameLocation":"2654:6:22","nodeType":"VariableDeclaration","scope":39729,"src":"2646:14:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39709,"name":"uint256","nodeType":"ElementaryTypeName","src":"2646:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39712,"initialValue":{"id":39711,"name":"_packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39618,"src":"2663:7:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"2646:24:22"},{"expression":{"id":39718,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39713,"name":"flashblockIndex","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39705,"src":"2680:15:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":39716,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39710,"src":"2704:6:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39715,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2698:5:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint8_$","typeString":"type(uint8)"},"typeName":{"id":39714,"name":"uint8","nodeType":"ElementaryTypeName","src":"2698:5:22","typeDescriptions":{}}},"id":39717,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2698:13:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"src":"2680:31:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"id":39719,"nodeType":"ExpressionStatement","src":"2680:31:22"},{"expression":{"id":39727,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":39720,"name":"blockNumber","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39707,"src":"2721:11:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":39725,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"id":39723,"name":"packed","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":39710,"src":"2742:6:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":">>","rightExpression":{"hexValue":"38","id":39724,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"2752:1:22","typeDescriptions":{"typeIdentifier":"t_rational_8_by_1","typeString":"int_const 8"},"value":"8"},"src":"2742:11:22","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":39722,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2735:6:22","typeDescriptions":{"typeIdentifier":"t_type$_t_uint48_$","typeString":"type(uint48)"},"typeName":{"id":39721,"name":"uint48","nodeType":"ElementaryTypeName","src":"2735:6:22","typeDescriptions":{}}},"id":39726,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2735:19:22","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"src":"2721:33:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"id":39728,"nodeType":"ExpressionStatement","src":"2721:33:22"}]},"documentation":{"id":39702,"nodeType":"StructuredDocumentation","src":"2338:212:22","text":"@notice Returns the last stored flashblock index and its associated block number.\n @return flashblockIndex The flashblock index.\n @return blockNumber The block number at which the index was set."},"functionSelector":"6d4ce63c","implemented":true,"kind":"function","modifiers":[],"name":"get","nameLocation":"2564:3:22","parameters":{"id":39703,"nodeType":"ParameterList","parameters":[],"src":"2567:2:22"},"returnParameters":{"id":39708,"nodeType":"ParameterList","parameters":[{"constant":false,"id":39705,"mutability":"mutable","name":"flashblockIndex","nameLocation":"2599:15:22","nodeType":"VariableDeclaration","scope":39730,"src":"2593:21:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":39704,"name":"uint8","nodeType":"ElementaryTypeName","src":"2593:5:22","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":39707,"mutability":"mutable","name":"blockNumber","nameLocation":"2623:11:22","nodeType":"VariableDeclaration","scope":39730,"src":"2616:18:22","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"},"typeName":{"id":39706,"name":"uint48","nodeType":"ElementaryTypeName","src":"2616:6:22","typeDescriptions":{"typeIdentifier":"t_uint48","typeString":"uint48"}},"visibility":"internal"}],"src":"2592:43:22"},"scope":39731,"stateMutability":"view","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[{"baseName":{"id":39591,"name":"Initializable","nodeType":"IdentifierPath","referencedDeclaration":39288,"src":"543:13:22"},"id":39592,"nodeType":"InheritanceSpecifier","src":"543:13:22"},{"baseName":{"id":39593,"name":"ISemver","nodeType":"IdentifierPath","referencedDeclaration":9,"src":"558:7:22"},"id":39594,"nodeType":"InheritanceSpecifier","src":"558:7:22"}],"canonicalName":"FlashblockIndex","contractDependencies":[],"contractKind":"contract","documentation":{"id":39590,"nodeType":"StructuredDocumentation","src":"205:310:22","text":"@custom:upgradeable\n @title FlashblockIndex\n @notice Stores the current flashblock index alongside block.number.\n @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8).\n Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write."},"fullyImplemented":true,"linearizedBaseContracts":[39731,9,39288],"name":"FlashblockIndex","nameLocation":"524:15:22","scope":39732,"usedErrors":[39597,39600]}],"license":"MIT"},"id":22} \ No newline at end of file +{ + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "builder", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "fallback", + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "BUILDER", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "get", + "inputs": [], + "outputs": [ + { + "name": "flashblockIndex", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "blockNumber", + "type": "uint48", + "internalType": "uint48" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, + { + "type": "event", + "name": "FlashblockIndexUpdated", + "inputs": [ + { + "name": "flashblockIndex", + "type": "uint8", + "indexed": true, + "internalType": "uint8" + }, + { + "name": "blockNumber", + "type": "uint48", + "indexed": true, + "internalType": "uint48" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint8", + "indexed": false, + "internalType": "uint8" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "InvalidCalldata", + "inputs": [] + }, + { + "type": "error", + "name": "OnlyBuilder", + "inputs": [] + } + ], + "bytecode": { + "object": "0x60a060405234801561001057600080fd5b506040516105dc3803806105dc83398101604081905261002f9161010a565b6001600160a01b03811660805261004461004a565b5061013a565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015610108576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011c57600080fd5b81516001600160a01b038116811461013357600080fd5b9392505050565b60805161048161015b60003960008181606401526101fd01526104816000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a" + }, + "deployedBytecode": { + "object": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a" + } +} diff --git a/justfile b/justfile index 45fd3ac79..a9d759904 100644 --- a/justfile +++ b/justfile @@ -222,6 +222,72 @@ snapshots-no-build: snapshots-abi-storage-no-build semver-lock-no-build snapshots: build-source snapshots-no-build + +######################################################## +# BINDINGS # +######################################################## + +# Adds a new Rust binding for a Solidity contract. +# Usage: just bindings-add src/L2/FlashblockIndex.sol +bindings-add SOL_PATH: build-source + #!/bin/bash + set -euo pipefail + + sol_path="{{SOL_PATH}}" + + # Extract contract name (e.g. FlashblockIndex from src/L2/FlashblockIndex.sol) + contract=$(basename "$sol_path" .sol) + + # Extract module (e.g. l2 from src/L2/FlashblockIndex.sol) + module=$(echo "$sol_path" | sed 's|^src/||' | xargs dirname | tr '[:upper:]' '[:lower:]') + + # Convert ContractName to snake_case (e.g. FlashblockIndex -> flashblock_index) + snake=$(echo "$contract" | sed 's/\([A-Z]\)/_\L\1/g' | sed 's/^_//') + + rust_dir="bindings/rust/src/${module}" + rust_file="${rust_dir}/${snake}.rs" + mod_file="${rust_dir}/mod.rs" + artifact="bindings/rust/artifacts/${contract}.json" + + # 1. Strip artifact + jq '{abi, bytecode: {object: .bytecode.object}, deployedBytecode: {object: .deployedBytecode.object}}' \ + "forge-artifacts/${contract}.sol/${contract}.json" > "$artifact" + + # 2. Create module directory if needed + mkdir -p "$rust_dir" + + # 3. Create .rs file + cat > "$rust_file" << EOF + use alloy_sol_types::sol; + + sol!( + #[sol(rpc, abi)] + ${contract}, + concat!( + env!("CARGO_MANIFEST_DIR"), + "/artifacts/${contract}.json" + ) + ); + EOF + + # 4. Add to mod.rs (skip if already present) + if ! grep -q "mod ${snake};" "$mod_file" 2>/dev/null; then + echo "" >> "$mod_file" + echo "mod ${snake};" >> "$mod_file" + echo "pub use ${snake}::${contract};" >> "$mod_file" + fi + + # 5. Add module to lib.rs (skip if already present) + if ! grep -q "pub mod ${module};" "bindings/rust/src/lib.rs" 2>/dev/null; then + echo "pub mod ${module};" >> "bindings/rust/src/lib.rs" + fi + + # 6. Format generated code + cd bindings/rust && cargo fmt + + echo "Added binding: ${contract} -> ${rust_file}" + + ######################################################## # CHECKS # ######################################################## @@ -232,6 +298,17 @@ snapshots-check-no-build: snapshots-no-build # Checks if the snapshots are up to date. snapshots-check: build snapshots-check-no-build +# Checks that committed Rust binding artifacts match forge-artifacts. +bindings-artifacts-check-no-build: + #!/bin/bash + set -euo pipefail + for src in bindings/rust/artifacts/*.json; do + name=$(basename "$src" .json) + jq '{abi, bytecode: {object: .bytecode.object}, deployedBytecode: {object: .deployedBytecode.object}}' \ + "forge-artifacts/${name}.sol/${name}.json" > "$src" + done + git diff --exit-code bindings/rust/artifacts/ + # Checks interface correctness without building. interfaces-check-no-build: go run ./scripts/checks/interfaces @@ -338,7 +415,8 @@ check: validate-spacers-no-build \ reinitializer-check-no-build \ interfaces-check-no-build \ - lint-forge-tests-check-no-build + lint-forge-tests-check-no-build \ + bindings-artifacts-check-no-build ######################################################## # DEV TOOLS # From de2e8ee6564615011db5931ab47deb6c00528ac9 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Wed, 4 Mar 2026 17:03:36 +0000 Subject: [PATCH 12/18] chore: update semver-lock snapshot --- snapshots/semver-lock.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index 70c5bc813..d249bbc2c 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -75,6 +75,10 @@ "initCodeHash": "0xdaae3903628f760e36da47c8f8d75d20962d1811fb5129cb09eb01803e67c095", "sourceCodeHash": "0x95dd8da08e907fa398c98710bb12fda9fb50d9688c5d2144fd9a424c99e672c5" }, + "src/L2/FlashblockIndex.sol:FlashblockIndex": { + "initCodeHash": "0x16c2bc1f2e6526eac40de3636464f8f3899f087773cb63106f5ebea38ea2160e", + "sourceCodeHash": "0x71c264e6ef9cbcd9f82dcbddcda6ad8b253ab23b10b317caead4a0d6efa94b2c" + }, "src/L2/GasPriceOracle.sol:GasPriceOracle": { "initCodeHash": "0xf72c23d9c3775afd7b645fde429d09800622d329116feb5ff9829634655123ca", "sourceCodeHash": "0xb4d1bf3669ba87bbeaf4373145c7e1490478c4a05ba4838a524aa6f0ce7348a6" From 60974773a2f8b5ef2780e3973cf2089d2fc61013 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Thu, 5 Mar 2026 09:06:01 +0000 Subject: [PATCH 13/18] fix: use robust PascalCase to snake_case conversion in bindings-add --- justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index a9d759904..0a950fbd1 100644 --- a/justfile +++ b/justfile @@ -241,8 +241,8 @@ bindings-add SOL_PATH: build-source # Extract module (e.g. l2 from src/L2/FlashblockIndex.sol) module=$(echo "$sol_path" | sed 's|^src/||' | xargs dirname | tr '[:upper:]' '[:lower:]') - # Convert ContractName to snake_case (e.g. FlashblockIndex -> flashblock_index) - snake=$(echo "$contract" | sed 's/\([A-Z]\)/_\L\1/g' | sed 's/^_//') + # Convert PascalCase to snake_case by inserting _ at lower|upper and acronym|word boundaries + snake=$(echo "$contract" | sed -E 's/([a-z0-9])([A-Z])/\1_\2/g' | sed -E 's/([A-Z]+)([A-Z][a-z])/\1_\2/g' | tr '[:upper:]' '[:lower:]') rust_dir="bindings/rust/src/${module}" rust_file="${rust_dir}/${snake}.rs" From 5ee149c9b57f5219db20fd610e8e3eb125659894 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Thu, 5 Mar 2026 14:09:45 +0000 Subject: [PATCH 14/18] chore: remove Cargo.lock from library crate --- .gitignore | 1 + bindings/rust/Cargo.lock | 3621 -------------------------------------- 2 files changed, 1 insertion(+), 3621 deletions(-) delete mode 100644 bindings/rust/Cargo.lock diff --git a/.gitignore b/.gitignore index 2d2ee8362..89badc510 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ artifacts !bindings/rust/artifacts/ forge-artifacts target +Cargo.lock cache broadcast kout-proofs diff --git a/bindings/rust/Cargo.lock b/bindings/rust/Cargo.lock deleted file mode 100644 index 8cd1ba9b5..000000000 --- a/bindings/rust/Cargo.lock +++ /dev/null @@ -1,3621 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "alloy-chains" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" -dependencies = [ - "alloy-primitives", - "num_enum", - "strum", -] - -[[package]] -name = "alloy-consensus" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728" -dependencies = [ - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "alloy-trie", - "alloy-tx-macros", - "auto_impl", - "borsh", - "c-kzg", - "derive_more", - "either", - "k256", - "once_cell", - "rand 0.8.5", - "secp256k1", - "serde", - "serde_json", - "serde_with", - "thiserror", -] - -[[package]] -name = "alloy-consensus-any" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-contract" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca63b7125a981415898ffe2a2a696c83696c9c6bdb1671c8a912946bbd8e49e7" -dependencies = [ - "alloy-consensus", - "alloy-dyn-abi", - "alloy-json-abi", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", - "alloy-sol-types", - "alloy-transport", - "futures", - "futures-util", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-dyn-abi" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2db5c583aaef0255aa63a4fe827f826090142528bba48d1bf4119b62780cad" -dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-type-parser", - "alloy-sol-types", - "itoa", - "serde", - "serde_json", - "winnow", -] - -[[package]] -name = "alloy-eip2124" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "crc", - "serde", - "thiserror", -] - -[[package]] -name = "alloy-eip2930" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9441120fa82df73e8959ae0e4ab8ade03de2aaae61be313fbf5746277847ce25" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "borsh", - "serde", -] - -[[package]] -name = "alloy-eip7702" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2919c5a56a1007492da313e7a3b6d45ef5edc5d33416fdec63c0d7a2702a0d20" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "borsh", - "serde", - "thiserror", -] - -[[package]] -name = "alloy-eip7928" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8222b1d88f9a6d03be84b0f5e76bb60cd83991b43ad8ab6477f0e4a7809b98d" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "borsh", - "serde", -] - -[[package]] -name = "alloy-eips" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8" -dependencies = [ - "alloy-eip2124", - "alloy-eip2930", - "alloy-eip7702", - "alloy-eip7928", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "auto_impl", - "borsh", - "c-kzg", - "derive_more", - "either", - "serde", - "serde_with", - "sha2", - "thiserror", -] - -[[package]] -name = "alloy-json-abi" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" -dependencies = [ - "alloy-primitives", - "alloy-sol-type-parser", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-json-rpc" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff42cd777eea61f370c0b10f2648a1c81e0b783066cd7269228aa993afd487f7" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "http", - "serde", - "serde_json", - "thiserror", - "tracing", -] - -[[package]] -name = "alloy-network" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbca04f9b410fdc51aaaf88433cbac761213905a65fe832058bcf6690585762" -dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-types-any", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", - "alloy-sol-types", - "async-trait", - "auto_impl", - "derive_more", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-network-primitives" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-serde", - "serde", -] - -[[package]] -name = "alloy-primitives" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" -dependencies = [ - "alloy-rlp", - "bytes", - "cfg-if", - "const-hex", - "derive_more", - "foldhash 0.2.0", - "hashbrown 0.16.1", - "indexmap 2.13.0", - "itoa", - "k256", - "keccak-asm", - "paste", - "proptest", - "rand 0.9.2", - "rapidhash", - "ruint", - "rustc-hash", - "serde", - "sha3", -] - -[[package]] -name = "alloy-provider" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d181c8cc7cf4805d7e589bf4074d56d55064fa1a979f005a45a62b047616d870" -dependencies = [ - "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-client", - "alloy-rpc-types-eth", - "alloy-signer", - "alloy-sol-types", - "alloy-transport", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "either", - "futures", - "futures-utils-wasm", - "lru", - "parking_lot", - "pin-project", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "wasmtimer", -] - -[[package]] -name = "alloy-rlp" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93e50f64a77ad9c5470bf2ad0ca02f228da70c792a8f06634801e202579f35e" -dependencies = [ - "alloy-rlp-derive", - "arrayvec", - "bytes", -] - -[[package]] -name = "alloy-rlp-derive" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "alloy-rpc-client" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2792758a93ae32a32e9047c843d536e1448044f78422d71bf7d7c05149e103f" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives", - "alloy-transport", - "futures", - "pin-project", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "wasmtimer", -] - -[[package]] -name = "alloy-rpc-types-any" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd720b63f82b457610f2eaaf1f32edf44efffe03ae25d537632e7d23e7929e1a" -dependencies = [ - "alloy-consensus-any", - "alloy-rpc-types-eth", - "alloy-serde", -] - -[[package]] -name = "alloy-rpc-types-eth" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9" -dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rlp", - "alloy-serde", - "alloy-sol-types", - "itertools 0.13.0", - "serde", - "serde_json", - "serde_with", - "thiserror", -] - -[[package]] -name = "alloy-serde" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-signer" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2425c6f314522c78e8198979c8cbf6769362be4da381d4152ea8eefce383535d" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "either", - "elliptic-curve", - "k256", - "thiserror", -] - -[[package]] -name = "alloy-sol-macro" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" -dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "alloy-sol-macro-expander" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" -dependencies = [ - "alloy-json-abi", - "alloy-sol-macro-input", - "const-hex", - "heck", - "indexmap 2.13.0", - "proc-macro-error2", - "proc-macro2", - "quote", - "sha3", - "syn 2.0.117", - "syn-solidity", -] - -[[package]] -name = "alloy-sol-macro-input" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" -dependencies = [ - "alloy-json-abi", - "const-hex", - "dunce", - "heck", - "macro-string", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.117", - "syn-solidity", -] - -[[package]] -name = "alloy-sol-type-parser" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" -dependencies = [ - "serde", - "winnow", -] - -[[package]] -name = "alloy-sol-types" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64612d29379782a5dde6f4b6570d9c756d734d760c0c94c254d361e678a6591f" -dependencies = [ - "alloy-json-abi", - "alloy-primitives", - "alloy-sol-macro", - "serde", -] - -[[package]] -name = "alloy-transport" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa186e560d523d196580c48bf00f1bf62e63041f28ecf276acc22f8b27bb9f53" -dependencies = [ - "alloy-json-rpc", - "auto_impl", - "base64", - "derive_more", - "futures", - "futures-utils-wasm", - "parking_lot", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-trie" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7fd448ab0a017de542de1dcca7a58e7019fe0e7a34ed3f9543ebddf6aceffa" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "arrayvec", - "derive_more", - "nybbles", - "serde", - "smallvec", - "thiserror", - "tracing", -] - -[[package]] -name = "alloy-tx-macros" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "ark-ff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" -dependencies = [ - "ark-ff-asm 0.3.0", - "ark-ff-macros 0.3.0", - "ark-serialize 0.3.0", - "ark-std 0.3.0", - "derivative", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm 0.4.2", - "ark-ff-macros 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint", - "num-traits", - "paste", - "rustc_version 0.4.1", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" -dependencies = [ - "ark-ff-asm 0.5.0", - "ark-ff-macros 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "arrayvec", - "digest 0.10.7", - "educe", - "itertools 0.13.0", - "num-bigint", - "num-traits", - "paste", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-asm" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "ark-ff-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" -dependencies = [ - "num-bigint", - "num-traits", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "ark-serialize" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" -dependencies = [ - "ark-std 0.3.0", - "digest 0.9.0", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-std 0.4.0", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-serialize" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" -dependencies = [ - "ark-std 0.5.0", - "arrayvec", - "digest 0.10.7", - "num-bigint", -] - -[[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "ark-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" -dependencies = [ - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "auto_impl" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "base-contracts-bindings" -version = "0.1.0" -dependencies = [ - "alloy-contract", - "alloy-sol-types", -] - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - -[[package]] -name = "bitcoin-io" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" - -[[package]] -name = "bitcoin_hashes" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" -dependencies = [ - "bitcoin-io", - "hex-conservative", -] - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blst" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" -dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", -] - -[[package]] -name = "borsh" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byte-slice-cast" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -dependencies = [ - "serde", -] - -[[package]] -name = "c-kzg" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0f582957c24870b7bfd12bf562c40b4734b533cafbaf8ded31d6d85f462c01" -dependencies = [ - "blst", - "cc", - "glob", - "hex", - "libc", - "once_cell", - "serde", -] - -[[package]] -name = "cc" -version = "1.2.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "num-traits", - "serde", - "windows-link", -] - -[[package]] -name = "const-hex" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" -dependencies = [ - "cfg-if", - "cpufeatures", - "proptest", - "serde_core", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const_format" -version = "0.2.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "convert_case" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "darling" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "serde", - "strsim", - "syn 2.0.117", -] - -[[package]] -name = "darling_macro" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" -dependencies = [ - "powerfmt", - "serde_core", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 2.0.117", - "unicode-xid", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "serdect", - "signature", - "spki", -] - -[[package]] -name = "educe" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -dependencies = [ - "serde", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "serdect", - "subtle", - "zeroize", -] - -[[package]] -name = "enum-ordinalize" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fastrlp" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", -] - -[[package]] -name = "fastrlp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-executor" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", -] - -[[package]] -name = "futures-utils-wasm" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" - -[[package]] -name = "generic-array" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", - "serde", - "serde_core", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-conservative" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "js-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "serdect", - "sha2", -] - -[[package]] -name = "keccak" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "keccak-asm" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" -dependencies = [ - "digest 0.10.7", - "sha3-asm", -] - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.182" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "lru" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" -dependencies = [ - "hashbrown 0.16.1", -] - -[[package]] -name = "macro-string" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "nybbles" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" -dependencies = [ - "alloy-rlp", - "cfg-if", - "proptest", - "ruint", - "serde", - "smallvec", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "parity-scale-codec" -version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "const_format", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "rustversion", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pest" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" -dependencies = [ - "memchr", - "ucd-trie", -] - -[[package]] -name = "pin-project" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash", - "impl-codec", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" -dependencies = [ - "bit-set", - "bit-vec", - "bitflags", - "num-traits", - "rand 0.9.2", - "rand_chacha 0.9.0", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", - "unarray", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "serde", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", - "serde", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", - "serde", -] - -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core 0.9.5", -] - -[[package]] -name = "rapidhash" -version = "4.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" -dependencies = [ - "rustversion", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "ruint" -version = "1.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" -dependencies = [ - "alloy-rlp", - "ark-ff 0.3.0", - "ark-ff 0.4.2", - "ark-ff 0.5.0", - "bytes", - "fastrlp 0.3.1", - "fastrlp 0.4.0", - "num-bigint", - "num-integer", - "num-traits", - "parity-scale-codec", - "primitive-types", - "proptest", - "rand 0.8.5", - "rand 0.9.2", - "rlp", - "ruint-macro", - "serde_core", - "valuable", - "zeroize", -] - -[[package]] -name = "ruint-macro" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver 1.0.27", -] - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "rusty-fork" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" -dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", -] - -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "serdect", - "subtle", - "zeroize", -] - -[[package]] -name = "secp256k1" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" -dependencies = [ - "bitcoin_hashes", - "rand 0.8.5", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "semver-parser" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "serde_with" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" -dependencies = [ - "base64", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.13.0", - "schemars 0.9.0", - "schemars 1.2.1", - "serde_core", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "serdect" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" -dependencies = [ - "base16ct", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - -[[package]] -name = "sha3-asm" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b31139435f327c93c6038ed350ae4588e2c70a13d50599509fee6349967ba35a" -dependencies = [ - "cc", - "cfg-if", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn-solidity" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" -dependencies = [ - "paste", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix", - "windows-sys", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde_core", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" - -[[package]] -name = "time-macros" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" -dependencies = [ - "pin-project-lite", - "tokio-macros", -] - -[[package]] -name = "tokio-macros" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.23.10+spec-1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" -dependencies = [ - "indexmap 2.13.0", - "toml_datetime", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_parser" -version = "1.0.9+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" -dependencies = [ - "winnow", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wait-timeout" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" -dependencies = [ - "libc", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.117", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "semver 1.0.27", -] - -[[package]] -name = "wasmtimer" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" -dependencies = [ - "futures", - "js-sys", - "parking_lot", - "pin-utils", - "slab", - "wasm-bindgen", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "winnow" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.13.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.13.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.0", - "log", - "semver 1.0.27", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From cc50730364cce201765981a996cf5819cb56c51b Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Thu, 5 Mar 2026 14:39:42 +0000 Subject: [PATCH 15/18] chore: add CI step to verify Rust bindings compile --- .github/workflows/test.yml | 6 ++++++ justfile | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b627c1474..f5d33af51 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,12 @@ jobs: just semver-lock-no-build git diff --exit-code snapshots/semver-lock.json + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Check Rust bindings + run: just bindings-check + - name: Run Forge tests run: just test id: test diff --git a/justfile b/justfile index 0a950fbd1..54bcab6f8 100644 --- a/justfile +++ b/justfile @@ -298,6 +298,10 @@ snapshots-check-no-build: snapshots-no-build # Checks if the snapshots are up to date. snapshots-check: build snapshots-check-no-build +# Checks that the Rust bindings crate compiles. +bindings-check: + cd bindings/rust && cargo check + # Checks that committed Rust binding artifacts match forge-artifacts. bindings-artifacts-check-no-build: #!/bin/bash From a460315bcbd5439e4a5a19148cb2c20540890ccc Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 17 Mar 2026 09:00:18 +0000 Subject: [PATCH 16/18] chore: minor change + cleaning --- bindings/rust/artifacts/FlashblockIndex.json | 118 ------------------- bindings/rust/src/l2/flashblock_index.rs | 10 -- bindings/rust/src/l2/mod.rs | 2 - bindings/rust/src/lib.rs | 2 +- justfile | 14 +-- 5 files changed, 8 insertions(+), 138 deletions(-) delete mode 100644 bindings/rust/artifacts/FlashblockIndex.json delete mode 100644 bindings/rust/src/l2/flashblock_index.rs delete mode 100644 bindings/rust/src/l2/mod.rs diff --git a/bindings/rust/artifacts/FlashblockIndex.json b/bindings/rust/artifacts/FlashblockIndex.json deleted file mode 100644 index aa15b3d9a..000000000 --- a/bindings/rust/artifacts/FlashblockIndex.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "abi": [ - { - "type": "constructor", - "inputs": [ - { - "name": "builder", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "fallback", - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "BUILDER", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "get", - "inputs": [], - "outputs": [ - { - "name": "flashblockIndex", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "blockNumber", - "type": "uint48", - "internalType": "uint48" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "initialize", - "inputs": [], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "version", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "FlashblockIndexUpdated", - "inputs": [ - { - "name": "flashblockIndex", - "type": "uint8", - "indexed": true, - "internalType": "uint8" - }, - { - "name": "blockNumber", - "type": "uint48", - "indexed": true, - "internalType": "uint48" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Initialized", - "inputs": [ - { - "name": "version", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "InvalidCalldata", - "inputs": [] - }, - { - "type": "error", - "name": "OnlyBuilder", - "inputs": [] - } - ], - "bytecode": { - "object": "0x60a060405234801561001057600080fd5b506040516105dc3803806105dc83398101604081905261002f9161010a565b6001600160a01b03811660805261004461004a565b5061013a565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015610108576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011c57600080fd5b81516001600160a01b038116811461013357600080fd5b9392505050565b60805161048161015b60003960008181606401526101fd01526104816000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a" - }, - "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a" - } -} diff --git a/bindings/rust/src/l2/flashblock_index.rs b/bindings/rust/src/l2/flashblock_index.rs deleted file mode 100644 index 6976d89df..000000000 --- a/bindings/rust/src/l2/flashblock_index.rs +++ /dev/null @@ -1,10 +0,0 @@ -use alloy_sol_types::sol; - -sol!( - #[sol(rpc, abi)] - FlashblockIndex, - concat!( - env!("CARGO_MANIFEST_DIR"), - "/artifacts/FlashblockIndex.json" - ) -); diff --git a/bindings/rust/src/l2/mod.rs b/bindings/rust/src/l2/mod.rs deleted file mode 100644 index 15a59fd87..000000000 --- a/bindings/rust/src/l2/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod flashblock_index; -pub use flashblock_index::FlashblockIndex; diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index a9f32026d..8b1378917 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1 +1 @@ -pub mod l2; + diff --git a/justfile b/justfile index 54bcab6f8..972472e9b 100644 --- a/justfile +++ b/justfile @@ -249,14 +249,14 @@ bindings-add SOL_PATH: build-source mod_file="${rust_dir}/mod.rs" artifact="bindings/rust/artifacts/${contract}.json" + # Ensure output directories exist before writing generated files. + mkdir -p "bindings/rust/artifacts" "$rust_dir" + # 1. Strip artifact jq '{abi, bytecode: {object: .bytecode.object}, deployedBytecode: {object: .deployedBytecode.object}}' \ "forge-artifacts/${contract}.sol/${contract}.json" > "$artifact" - # 2. Create module directory if needed - mkdir -p "$rust_dir" - - # 3. Create .rs file + # 2. Create .rs file cat > "$rust_file" << EOF use alloy_sol_types::sol; @@ -270,19 +270,19 @@ bindings-add SOL_PATH: build-source ); EOF - # 4. Add to mod.rs (skip if already present) + # 3. Add to mod.rs (skip if already present) if ! grep -q "mod ${snake};" "$mod_file" 2>/dev/null; then echo "" >> "$mod_file" echo "mod ${snake};" >> "$mod_file" echo "pub use ${snake}::${contract};" >> "$mod_file" fi - # 5. Add module to lib.rs (skip if already present) + # 4. Add module to lib.rs (skip if already present) if ! grep -q "pub mod ${module};" "bindings/rust/src/lib.rs" 2>/dev/null; then echo "pub mod ${module};" >> "bindings/rust/src/lib.rs" fi - # 6. Format generated code + # 5. Format generated code cd bindings/rust && cargo fmt echo "Added binding: ${contract} -> ${rust_file}" From 6dcf6aa5fe32505c61aa12f51424952c8cd6a43d Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 17 Mar 2026 09:30:40 +0000 Subject: [PATCH 17/18] chore: remove FlashblockIndex contract --- src/L2/FlashblockIndex.sol | 63 ------------- test/L2/FlashblockIndex.t.sol | 172 ---------------------------------- 2 files changed, 235 deletions(-) delete mode 100644 src/L2/FlashblockIndex.sol delete mode 100644 test/L2/FlashblockIndex.t.sol diff --git a/src/L2/FlashblockIndex.sol b/src/L2/FlashblockIndex.sol deleted file mode 100644 index eccc5a0c2..000000000 --- a/src/L2/FlashblockIndex.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import { ISemver } from "interfaces/universal/ISemver.sol"; - -/// @custom:upgradeable -/// @title FlashblockIndex -/// @notice Stores the current flashblock index alongside block.number. -/// @dev The builder calls this via fallback with 1 byte of calldata (the index as uint8). -/// Both values are manually packed into a single uint256 to guarantee 1 SSTORE per write. -contract FlashblockIndex is Initializable, ISemver { - /// @notice Thrown when the caller is not the authorized builder. - error OnlyBuilder(); - - /// @notice Thrown when calldata is not exactly 1 byte. - error InvalidCalldata(); - - /// @notice Emitted when the flashblock index is updated. - /// @param flashblockIndex The new flashblock index. - /// @param blockNumber The block number at which the index was set. - event FlashblockIndexUpdated(uint8 indexed flashblockIndex, uint48 indexed blockNumber); - - /// @notice Semantic version. - /// @custom:semver 1.0.0 - string public constant override version = "1.0.0"; - - /// @notice The authorized builder address, set at deploy time. - address public immutable BUILDER; - - /// @notice Packed storage: blockNumber (uint48) in bits [55:8] | flashblockIndex (uint8) in bits [7:0]. - /// @dev Using uint48 for block numbers is safe for the foreseeable future (~281 trillion blocks). - uint256 private _packed; - - /// @notice Constructor. - /// @param builder The address authorized to update the flashblock index. - constructor(address builder) { - BUILDER = builder; - _disableInitializers(); - } - - /// @notice Initializer. - function initialize() external initializer { } - - /// @notice Sets the flashblock index for the current block. - /// @dev Calldata must be exactly 1 byte representing the flashblock index (uint8). - /// Stores `(block.number << 8) | index` in a single SSTORE. - fallback() external { - if (msg.sender != BUILDER) revert OnlyBuilder(); - if (msg.data.length != 1) revert InvalidCalldata(); - _packed = (uint256(uint48(block.number)) << 8) | uint256(uint8(msg.data[0])); - emit FlashblockIndexUpdated(uint8(msg.data[0]), uint48(block.number)); - } - - /// @notice Returns the last stored flashblock index and its associated block number. - /// @return flashblockIndex The flashblock index. - /// @return blockNumber The block number at which the index was set. - function get() external view returns (uint8 flashblockIndex, uint48 blockNumber) { - uint256 packed = _packed; - flashblockIndex = uint8(packed); - blockNumber = uint48(packed >> 8); - } -} diff --git a/test/L2/FlashblockIndex.t.sol b/test/L2/FlashblockIndex.t.sol deleted file mode 100644 index 1739a49ac..000000000 --- a/test/L2/FlashblockIndex.t.sol +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { Test } from "forge-std/Test.sol"; -import { FlashblockIndex } from "src/L2/FlashblockIndex.sol"; - -contract FlashblockIndexTest is Test { - event FlashblockIndexUpdated(uint8 indexed flashblockIndex, uint48 indexed blockNumber); - - FlashblockIndex flashblockIndex; - address builder; - - function setUp() public { - builder = makeAddr("builder"); - flashblockIndex = new FlashblockIndex(builder); - } - - /// @notice Tests that the constructor correctly sets the BUILDER immutable. - function test_constructor_setsBuilder() external view { - assertEq(flashblockIndex.BUILDER(), builder); - } - - /// @notice Tests that initialize() reverts on the implementation contract since initializers are disabled. - function test_initialize_reverts_whenCalledOnImplementation() external { - vm.expectRevert("Initializable: contract is already initialized"); - flashblockIndex.initialize(); - } - - /// @notice Tests that version() returns "1.0.0". - function test_version_returnsCorrectValue() external view { - assertEq(flashblockIndex.version(), "1.0.0"); - } - - /// @notice Tests that get() returns (0, 0) when no index has ever been written. - function test_get_returnsZeros_whenNeverWritten() external view { - (uint8 index, uint48 blockNumber) = flashblockIndex.get(); - assertEq(index, 0); - assertEq(blockNumber, 0); - } - - /// @notice Tests that get() returns the correct index and block number after a write. - function test_get_returnsCorrectValues(uint8 index, uint48 blockNumber) external { - vm.roll(blockNumber); - (bool success,) = _callFallback({ caller: builder, index: index }); - assertTrue(success); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, index); - assertEq(actualBlock, blockNumber); - } - - /// @notice Tests that the fallback reverts with OnlyBuilder when called by a non-builder address. - function test_fallback_reverts_whenCallerIsNotBuilder(address caller, uint8 index) external { - vm.assume(caller != builder); - (bool success, bytes memory returnData) = _callFallback({ caller: caller, index: index }); - assertFalse(success); - assertEq(bytes4(returnData), FlashblockIndex.OnlyBuilder.selector); - } - - /// @notice Tests that the fallback reverts with InvalidCalldata when called with zero bytes. - function test_fallback_reverts_whenCalldataIsEmpty() external { - vm.prank(builder); - (bool success, bytes memory returnData) = address(flashblockIndex).call(""); - assertFalse(success); - assertEq(bytes4(returnData), FlashblockIndex.InvalidCalldata.selector); - } - - /// @notice Tests that the fallback reverts with InvalidCalldata when called with more than 1 byte. - function test_fallback_reverts_whenCalldataIsTooLong(uint8 extra) external { - vm.prank(builder); - (bool success, bytes memory returnData) = address(flashblockIndex).call(abi.encodePacked(uint8(1), extra)); - assertFalse(success); - assertEq(bytes4(returnData), FlashblockIndex.InvalidCalldata.selector); - } - - /// @notice Tests that the fallback stores the index and block number correctly when called by the builder. - function test_fallback_setsIndex(uint8 index, uint48 blockNumber) external { - vm.roll(blockNumber); - (bool success,) = _callFallback({ caller: builder, index: index }); - assertTrue(success); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, index); - assertEq(actualBlock, blockNumber); - } - - /// @notice Tests that the fallback emits FlashblockIndexUpdated with the correct parameters. - function test_fallback_emitsFlashblockIndexUpdated(uint8 index, uint48 blockNumber) external { - vm.roll(blockNumber); - vm.expectEmit(address(flashblockIndex)); - emit FlashblockIndexUpdated(index, blockNumber); - (bool success,) = _callFallback({ caller: builder, index: index }); - assertTrue(success); - } - - /// @notice Tests that a second fallback call overwrites the previous value at a different block. - function test_fallback_overwritesPreviousValue() external { - uint48 firstBlock = 100; - uint8 firstIndex = 5; - vm.roll(firstBlock); - (bool s1,) = _callFallback({ caller: builder, index: firstIndex }); - assertTrue(s1); - - uint48 secondBlock = 200; - uint8 secondIndex = 10; - vm.roll(secondBlock); - (bool s2,) = _callFallback({ caller: builder, index: secondIndex }); - assertTrue(s2); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, secondIndex); - assertEq(actualBlock, secondBlock); - } - - /// @notice Tests that a second fallback call overwrites the previous value within the same block. - function test_fallback_overwritesWithinSameBlock() external { - uint48 blockNumber = 100; - uint8 firstIndex = 5; - uint8 secondIndex = 10; - - vm.roll(blockNumber); - (bool s1,) = _callFallback({ caller: builder, index: firstIndex }); - assertTrue(s1); - - (bool s2,) = _callFallback({ caller: builder, index: secondIndex }); - assertTrue(s2); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, secondIndex); - assertEq(actualBlock, blockNumber); - } - - /// @notice Tests that the fallback correctly stores the maximum uint48 block number. - function test_fallback_storesMaxBlockNumber() external { - uint48 maxBlock = type(uint48).max; - uint8 index = 1; - - vm.roll(maxBlock); - (bool success,) = _callFallback({ caller: builder, index: index }); - assertTrue(success); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, index); - assertEq(actualBlock, maxBlock); - } - - /// @notice Tests that the block number is truncated to uint48 when it exceeds the max value. - function test_fallback_truncatesBlockNumber() external { - uint256 overflowBlock = uint256(type(uint48).max) + 1; - uint8 index = 1; - - vm.roll(overflowBlock); - (bool success,) = _callFallback({ caller: builder, index: index }); - assertTrue(success); - - (uint8 actualIndex, uint48 actualBlock) = flashblockIndex.get(); - assertEq(actualIndex, index); - assertEq(actualBlock, 0); - } - - // --- Helper --- - - /// @notice Helper function to call the fallback with the given caller and index. - /// @param caller The address of the caller. - /// @param index The index to call the fallback with. - /// @return success True if the fallback call succeeded. - /// @return returnData The return data from the fallback call. - function _callFallback(address caller, uint8 index) private returns (bool success, bytes memory returnData) { - vm.prank(caller); - (success, returnData) = address(flashblockIndex).call(abi.encodePacked(index)); - } -} From 7f575f753d289ee37e752ad96ade14282b5f2948 Mon Sep 17 00:00:00 2001 From: Baptiste Oueriagli Date: Tue, 17 Mar 2026 09:33:47 +0000 Subject: [PATCH 18/18] chore: regenerate snapshots --- snapshots/abi/NitroEnclaveVerifier.json | 1263 +++++++++++++++++ snapshots/semver-lock.json | 24 - .../storageLayout/NitroEnclaveVerifier.json | 65 + 3 files changed, 1328 insertions(+), 24 deletions(-) create mode 100644 snapshots/abi/NitroEnclaveVerifier.json create mode 100644 snapshots/storageLayout/NitroEnclaveVerifier.json diff --git a/snapshots/abi/NitroEnclaveVerifier.json b/snapshots/abi/NitroEnclaveVerifier.json new file mode 100644 index 000000000..9f2b98569 --- /dev/null +++ b/snapshots/abi/NitroEnclaveVerifier.json @@ -0,0 +1,1263 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "uint64", + "name": "_maxTimeDiff", + "type": "uint64" + }, + { + "internalType": "bytes32[]", + "name": "_initializeTrustedCerts", + "type": "bytes32[]" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "_verifier", + "type": "address" + } + ], + "name": "addVerifyRoute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoprocessor", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + } + ], + "name": "batchVerify", + "outputs": [ + { + "components": [ + { + "internalType": "enum VerificationResult", + "name": "result", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "trustedCertsPrefixLen", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "timestamp", + "type": "uint64" + }, + { + "internalType": "bytes32[]", + "name": "certs", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "nonce", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "first", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "second", + "type": "bytes16" + } + ], + "internalType": "struct Bytes48", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Pcr[]", + "name": "pcrs", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "moduleId", + "type": "string" + } + ], + "internalType": "struct VerifierJournal[]", + "name": "results", + "type": "tuple[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cancelOwnershipHandover", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[][]", + "name": "_report_certs", + "type": "bytes32[][]" + } + ], + "name": "checkTrustedIntermediateCerts", + "outputs": [ + { + "internalType": "uint8[]", + "name": "", + "type": "uint8[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pendingOwner", + "type": "address" + } + ], + "name": "completeOwnershipHandover", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "freezeVerifyRoute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + } + ], + "name": "getAggregatorIds", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + } + ], + "name": "getVerifierIds", + "outputs": [ + { + "internalType": "bytes32[]", + "name": "", + "type": "bytes32[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_verifierId", + "type": "bytes32" + } + ], + "name": "getVerifierProofId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + } + ], + "name": "getZkConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "verifierId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "aggregatorId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "zkVerifier", + "type": "address" + } + ], + "internalType": "struct ZkCoProcessorConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes4", + "name": "_selector", + "type": "bytes4" + } + ], + "name": "getZkVerifier", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_aggregatorId", + "type": "bytes32" + } + ], + "name": "isAggregatorIdSupported", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_verifierId", + "type": "bytes32" + } + ], + "name": "isVerifierIdSupported", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxTimeDiff", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "result", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pendingOwner", + "type": "address" + } + ], + "name": "ownershipHandoverExpiresAt", + "outputs": [ + { + "internalType": "uint256", + "name": "result", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proofSubmitter", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_aggregatorId", + "type": "bytes32" + } + ], + "name": "removeAggregatorId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_verifierId", + "type": "bytes32" + } + ], + "name": "removeVerifierId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "requestOwnershipHandover", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_certHash", + "type": "bytes32" + } + ], + "name": "revokeCert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rootCert", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_maxTimeDiff", + "type": "uint64" + } + ], + "name": "setMaxTimeDiff", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_proofSubmitter", + "type": "address" + } + ], + "name": "setProofSubmitter", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_rootCert", + "type": "bytes32" + } + ], + "name": "setRootCert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "verifierId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "aggregatorId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "zkVerifier", + "type": "address" + } + ], + "internalType": "struct ZkCoProcessorConfig", + "name": "_config", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "_verifierProofId", + "type": "bytes32" + } + ], + "name": "setZkConfiguration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "trustedCertHash", + "type": "bytes32" + } + ], + "name": "trustedIntermediateCerts", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_newAggregatorId", + "type": "bytes32" + } + ], + "name": "updateAggregatorId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "_zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "_newVerifierId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "_newVerifierProofId", + "type": "bytes32" + } + ], + "name": "updateVerifierId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoprocessor", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + } + ], + "name": "verify", + "outputs": [ + { + "components": [ + { + "internalType": "enum VerificationResult", + "name": "result", + "type": "uint8" + }, + { + "internalType": "uint8", + "name": "trustedCertsPrefixLen", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "timestamp", + "type": "uint64" + }, + { + "internalType": "bytes32[]", + "name": "certs", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "nonce", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "index", + "type": "uint64" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "first", + "type": "bytes32" + }, + { + "internalType": "bytes16", + "name": "second", + "type": "bytes16" + } + ], + "internalType": "struct Bytes48", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct Pcr[]", + "name": "pcrs", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "moduleId", + "type": "string" + } + ], + "internalType": "struct VerifierJournal", + "name": "journal", + "type": "tuple" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "", + "type": "uint8" + } + ], + "name": "zkConfig", + "outputs": [ + { + "internalType": "bytes32", + "name": "verifierId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "aggregatorId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "zkVerifier", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newId", + "type": "bytes32" + } + ], + "name": "AggregatorIdUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum VerificationResult", + "name": "result", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "output", + "type": "bytes" + } + ], + "name": "AttestationSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "verifierId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "encodedBatch", + "type": "bytes" + } + ], + "name": "BatchAttestationSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "certHash", + "type": "bytes32" + } + ], + "name": "CertRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "newMaxTimeDiff", + "type": "uint64" + } + ], + "name": "MaxTimeDiffUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pendingOwner", + "type": "address" + } + ], + "name": "OwnershipHandoverCanceled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pendingOwner", + "type": "address" + } + ], + "name": "OwnershipHandoverRequested", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "programId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAggregator", + "type": "bool" + } + ], + "name": "ProgramIdRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newProofSubmitter", + "type": "address" + } + ], + "name": "ProofSubmitterChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "newRootCert", + "type": "bytes32" + } + ], + "name": "RootCertChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "newProofId", + "type": "bytes32" + } + ], + "name": "VerifierIdUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "verifierId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "aggregatorId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "zkVerifier", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct ZkCoProcessorConfig", + "name": "config", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "verifierProofId", + "type": "bytes32" + } + ], + "name": "ZKConfigurationUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "ZkRouteAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "indexed": true, + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "ZkRouteWasFrozen", + "type": "event" + }, + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "CallerNotProofSubmitter", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "identifier", + "type": "bytes32" + } + ], + "name": "CannotRemoveLatestProgramId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "certHash", + "type": "bytes32" + } + ], + "name": "CertificateNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "NewOwnerIsZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "NoHandoverRequest", + "type": "error" + }, + { + "inputs": [], + "name": "NotImplemented", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "identifier", + "type": "bytes32" + } + ], + "name": "ProgramIdAlreadyLatest", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "identifier", + "type": "bytes32" + } + ], + "name": "ProgramIdNotFound", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "RootCertMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "Unknown_Zk_Coprocessor", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "expected", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "actual", + "type": "bytes32" + } + ], + "name": "VerifierVkMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroMaxTimeDiff", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroProgramId", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroProofSubmitter", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroVerifierAddress", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + }, + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "ZkRouteFrozen", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "enum ZkCoProcessorType", + "name": "zkCoProcessor", + "type": "uint8" + } + ], + "name": "ZkVerifierNotConfigured", + "type": "error" + } +] \ No newline at end of file diff --git a/snapshots/semver-lock.json b/snapshots/semver-lock.json index d249bbc2c..cab2951cd 100644 --- a/snapshots/semver-lock.json +++ b/snapshots/semver-lock.json @@ -11,10 +11,6 @@ "initCodeHash": "0xe52c51805cfd55967d037173159f18aaf4344e32e5c8ad41f8d5d0025b1d36a8", "sourceCodeHash": "0xe5f2b1915a201c0b8a107f168f5b9bc8aec8e8e95f938082e42ba5b5c8ebbd11" }, - "src/L1/FeesDepositor.sol:FeesDepositor:dispute": { - "initCodeHash": "0xe52c51805cfd55967d037173159f18aaf4344e32e5c8ad41f8d5d0025b1d36a8", - "sourceCodeHash": "0xe5f2b1915a201c0b8a107f168f5b9bc8aec8e8e95f938082e42ba5b5c8ebbd11" - }, "src/L1/L1CrossDomainMessenger.sol:L1CrossDomainMessenger": { "initCodeHash": "0x3dc659aafb03bd357f92abfc6794af89ee0ddd5212364551637422bf8d0b00f9", "sourceCodeHash": "0xfd67aae7ef1d684f3fccc036a80123e0ffa13de3e26c910cb7b927059c5a6289" @@ -51,10 +47,6 @@ "initCodeHash": "0x9b1f3555b499709485d51d5d9665002c0eb1e5eb893be1fb978a30749e894858", "sourceCodeHash": "0x572b5da38443fa5fc1c1873a733adee1894c6eba94f0e7867f2e81c5eb616a39" }, - "src/L1/SuperchainConfig.sol:SuperchainConfig:dispute": { - "initCodeHash": "0x9b1f3555b499709485d51d5d9665002c0eb1e5eb893be1fb978a30749e894858", - "sourceCodeHash": "0x572b5da38443fa5fc1c1873a733adee1894c6eba94f0e7867f2e81c5eb616a39" - }, "src/L1/SystemConfig.sol:SystemConfig": { "initCodeHash": "0x3e8e52d96398a6de91d8922769cc5d0bc7acb2a692689ceb70f1de816e8d6b14", "sourceCodeHash": "0x1a24ffe154eddbe0088a4b0848e662bf5eb482fe031ba528f74c51804f6e0395" @@ -75,10 +67,6 @@ "initCodeHash": "0xdaae3903628f760e36da47c8f8d75d20962d1811fb5129cb09eb01803e67c095", "sourceCodeHash": "0x95dd8da08e907fa398c98710bb12fda9fb50d9688c5d2144fd9a424c99e672c5" }, - "src/L2/FlashblockIndex.sol:FlashblockIndex": { - "initCodeHash": "0x16c2bc1f2e6526eac40de3636464f8f3899f087773cb63106f5ebea38ea2160e", - "sourceCodeHash": "0x71c264e6ef9cbcd9f82dcbddcda6ad8b253ab23b10b317caead4a0d6efa94b2c" - }, "src/L2/GasPriceOracle.sol:GasPriceOracle": { "initCodeHash": "0xf72c23d9c3775afd7b645fde429d09800622d329116feb5ff9829634655123ca", "sourceCodeHash": "0xb4d1bf3669ba87bbeaf4373145c7e1490478c4a05ba4838a524aa6f0ce7348a6" @@ -247,26 +235,14 @@ "initCodeHash": "0xc3866b1d4515c9d7b0ac6679b182d836f79371402d9e649e301b24cf8ae8fade", "sourceCodeHash": "0x98267b52a71222506c4893d6632dc5a36dd197a8d60de9a1f6578a80f7ebdf2d" }, - "src/multiproof/AggregateVerifier.sol:AggregateVerifier:dispute": { - "initCodeHash": "0xe28eaeecda21594f6db23bb70127daa2b7b71debe38ce65b598f28d78d2561eb", - "sourceCodeHash": "0x98267b52a71222506c4893d6632dc5a36dd197a8d60de9a1f6578a80f7ebdf2d" - }, "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry": { "initCodeHash": "0x09760f3a16c82db6a0e292a394d8a97cc34cc4aa799aeee9c1e064c9e8181050", "sourceCodeHash": "0xae23e7c3e21c373d491a0e496ece54c63b5ad09171db1a011011eae3e2831c72" }, - "src/multiproof/tee/TEEProverRegistry.sol:TEEProverRegistry:dispute": { - "initCodeHash": "0x7345fbc8139f09132ad1ee8432a0e30361e6e92b2cca18855cec81093f5f4ea7", - "sourceCodeHash": "0xae23e7c3e21c373d491a0e496ece54c63b5ad09171db1a011011eae3e2831c72" - }, "src/multiproof/tee/TEEVerifier.sol:TEEVerifier": { "initCodeHash": "0xd65f1d604f979045a86d662e168cb7a867478da8a0ca294181872a90d209a66f", "sourceCodeHash": "0xe8aa3c0710ee72546da52957730c11dc932065c444a013658bd2f5fd0c79085d" }, - "src/multiproof/tee/TEEVerifier.sol:TEEVerifier:dispute": { - "initCodeHash": "0xd65f1d604f979045a86d662e168cb7a867478da8a0ca294181872a90d209a66f", - "sourceCodeHash": "0xe8aa3c0710ee72546da52957730c11dc932065c444a013658bd2f5fd0c79085d" - }, "src/revenue-share/FeeDisburser.sol:FeeDisburser": { "initCodeHash": "0x1278027e3756e2989e80c0a7b513e221a5fe0d3dbd9ded108375a29b2c1f3d57", "sourceCodeHash": "0xac49a0ecf22b8a7bb3ebef830a2d27b19050f9b08941186e8563d5113cf0ce9c" diff --git a/snapshots/storageLayout/NitroEnclaveVerifier.json b/snapshots/storageLayout/NitroEnclaveVerifier.json new file mode 100644 index 000000000..0feab09c3 --- /dev/null +++ b/snapshots/storageLayout/NitroEnclaveVerifier.json @@ -0,0 +1,65 @@ +[ + { + "bytes": "20", + "label": "proofSubmitter", + "offset": 0, + "slot": "0", + "type": "address" + }, + { + "bytes": "32", + "label": "zkConfig", + "offset": 0, + "slot": "1", + "type": "mapping(enum ZkCoProcessorType => struct ZkCoProcessorConfig)" + }, + { + "bytes": "32", + "label": "trustedIntermediateCerts", + "offset": 0, + "slot": "2", + "type": "mapping(bytes32 => bool)" + }, + { + "bytes": "8", + "label": "maxTimeDiff", + "offset": 0, + "slot": "3", + "type": "uint64" + }, + { + "bytes": "32", + "label": "rootCert", + "offset": 0, + "slot": "4", + "type": "bytes32" + }, + { + "bytes": "32", + "label": "_verifierIdSet", + "offset": 0, + "slot": "5", + "type": "mapping(enum ZkCoProcessorType => struct EnumerableSet.Bytes32Set)" + }, + { + "bytes": "32", + "label": "_aggregatorIdSet", + "offset": 0, + "slot": "6", + "type": "mapping(enum ZkCoProcessorType => struct EnumerableSet.Bytes32Set)" + }, + { + "bytes": "32", + "label": "_zkVerifierRoutes", + "offset": 0, + "slot": "7", + "type": "mapping(enum ZkCoProcessorType => mapping(bytes4 => address))" + }, + { + "bytes": "32", + "label": "_verifierProofIds", + "offset": 0, + "slot": "8", + "type": "mapping(enum ZkCoProcessorType => mapping(bytes32 => bytes32))" + } +] \ No newline at end of file